从属fd被另一个应用程序(例如“A”)用作串行端口设备。

A将设置其波特率/停止位等。我的应用程序需要此信息。

顺便说一句,有什么方法可以让仅打开主fd的进程收到发给从fd的所有ioctl()调用的通知?

最佳答案

是的,这是可能的(在Linux和2004之前的FreeBSD中),可以在数据包模式下使用pty并在其上设置EXTPROC标志。

  • 在主机端通过ioctl(master, TIOCPKT, &nonzero)启用数据包模式。现在,主端上的每个read都将产生一个数据包:在另一侧写的任何内容,再加上一个状态字节,该状态字节说明从属端的情况(“将刷新终端(即从属端)的写入队列“)
  • 但是,这并不意味着主机立即知道从机端的更改,例如这些更改发生后,主服务器上的select()不会立即返回,仅当需要读取
  • 时才返回
  • 但是,在pty的本地标志字中设置EXTPROC之后-使用tcsetattr()-随从状态更改后,select()将立即返回,然后可以检查从属终端-通过直接在父进程中保持打开状态的从属fd ,或者至少在linux上,只需通过主端的tcgetattr()即可。
  • 请注意,EXTPROC会禁用pty驱动程序的某些部分,例如本地回显已关闭。

  • EXTPROC很少使用(here是一个可能的用例),不是很可移植,也没有任何文档记录(至少应该在linux termiostty_ioctl联机帮助页中的某处)。查看linux内核源drivers/tty/n_tty.c,我得出结论,从属termios结构中的任何更改都将使主端上的select()返回-但是不改变任何内容的tcsetattr()不会。

    编辑:为响应塞巴斯蒂安(J.F. Sebastians)的要求,我在下面提供了一个示例程序,该程序应阐明如何在Linux计算机上以数据包模式使用EXTRPOC:

    /* Demo program for managing a pty in packet mode with the slave's
    ** EXTPROC bit set, where the master gets notified of changes in the
    ** slaves terminal attributes
    **
    ** save as extproc.c, compile with gcc -o extproc extproc.c -lutil
    */
    
    
    
    #include <stdio.h>
    #include <pty.h>
    #include <termios.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    #include <sys/select.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    #define BUFSIZE 512
    
    void main() {
      int master;      // fd of master side
      pid_t pid;
      if((pid = forkpty(&master, NULL, NULL, NULL))) { // we're parent
        fd_set rfds, xfds;
        int retval, nread, status = 0, nonzero = 1;
        char buf[BUFSIZE];
    
        ioctl(master, TIOCPKT, &nonzero); // initiate packet mode - necessary to get notified of
                                          // ioctl() on the slave side
        while(1) {
          // set stdout unbuffered (we want to see stuff as it happens)
          setbuf(stdout, NULL);
    
          // prepare the file descriptor sets
          FD_ZERO(&rfds);
          FD_SET(master, &rfds);
    
          FD_ZERO(&xfds);
          FD_SET(master, &xfds);
    
          // now wait until status of master changes
          printf("---- waiting for something to happen -----\n");
          select(1 + master, &rfds, NULL, &xfds, NULL);
    
          char *r_text = (FD_ISSET(master, &rfds) ? "master ready for reading" : "- ");
          char *x_text = (FD_ISSET(master, &xfds) ? "exception on master" : "- ");
    
          printf("rfds: %s, xfds: %s\n", r_text, x_text);
          if ((nread = read(master, buf, BUFSIZE-1)) < 0)
            perror("read error");
          else {
            buf[nread] = '\0';
            // In packet mode *buf will be the status byte , and buf + 1 the "payload"
            char *pkt_txt = (*buf &  TIOCPKT_IOCTL ? " (TIOCPKT_IOCTL)" : "");
            printf("read %d bytes: status byte %x%s, payload <%s>\n", nread, *buf, pkt_txt, buf + 1);
          }
          if (waitpid(pid, &status, WNOHANG) && WIFEXITED(status)) {
            printf("child exited with status %x\n", status);
            exit(EXIT_SUCCESS);
          }
        }
      } else { // child
        struct termios tio;
    
        // First set the EXTPROC bit in the slave end termios structure
        tcgetattr(STDIN_FILENO, &tio);
        tio.c_lflag |= EXTPROC;
        tcsetattr(STDIN_FILENO, TCSANOW, &tio);
    
        // Wait a bit and do an ordinary write()
        sleep(1);
        write(STDOUT_FILENO,"blah", 4);
    
        // Wait a bit and change the pty terminal attributes. This will be picked up by the master end
        sleep(1);
        tio.c_cc[VINTR] = 0x07;
        tcsetattr(STDIN_FILENO, TCSANOW, &tio);
    
        // Wait a bit and exit
        sleep(1);
      }
    }
    

    输出将类似于:
    ---- waiting for something to happen -----
    rfds: master ready for reading, xfds: exception on master
    read 1 bytes: status byte 40 (TIOCPKT_IOCTL), payload <>
    ---- waiting for something to happen -----
    rfds: master ready for reading, xfds: -
    read 5 bytes: status byte 0, payload <blah>
    ---- waiting for something to happen -----
    rfds: master ready for reading, xfds: exception on master
    read 1 bytes: status byte 40 (TIOCPKT_IOCTL), payload <>
    ---- waiting for something to happen -----
    rfds: master ready for reading, xfds: -
    read error: Input/output error
    child exited with status 0
    

    通常,pty的主端不必是tty(并具有关联的termios结构),但是在Linux下,它是(具有共享的termios:一端的更改将同时更改两个termios结构)。

    这意味着我们可以修改上面的示例程序并在主端设置EXTPROC,这没有任何区别。

    据我所知,所有这些都没有记录在案,当然,甚至没有那么便携。

    关于linux - 通过 “tcsetattr”更改pty [Pseudo terminal]从属fd设置时,主控端如何立即捕获该事件?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21641754/

    10-13 08:37