当pty [伪终端]从属设备fd设置被"tcsetattr"改变时,将其设置为0. ,主机端如何立即捕获此事件? [英] When pty [Pseudo terminal] slave fd settings are changed by "tcsetattr" , how can the master end capture this event without delay?

查看:162
本文介绍了当pty [伪终端]从属设备fd设置被"tcsetattr"改变时,将其设置为0. ,主机端如何立即捕获此事件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从属fd由另一个应用程序(例如"A")用作串行端口设备.

The slave fd is used by another application (say "A") as a serial port device .

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

A will set its baud rate/stop bit etc. My app needs this information .

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

BTW, is there any way for a process that has only the master fd open to be notified of all ioctl() calls that are issued to the slave fd ?

推荐答案

是的,在分组模式下使用pty并在其上设置EXTPROC标志,这是可能的(在Linux和2004之前的FreeBSD中).

Yes, this is possible (in Linux and pre-2004 FreeBSD) , using the pty in packet mode and setting the EXTPROC flag on it.

  • 在主机端通过ioctl(master, TIOCPKT, &nonzero)启用分组模式.现在,主端上的每个read都将生成一个 packet :在另一侧写的任何内容,以及一个状态字节,该状态字节说明从属端的情况(终端(即从属端)已刷新")

  • Packet mode is enabled on the master end by ioctl(master, TIOCPKT, &nonzero). Now every read on the master end will yield a packet: whatever was written on the other side, plus a status byte that says something about the situation on the slave end ("The write queue for the terminal (i.e. the slave end) is flushed")

但这并不意味着主机立即知道从机端的更改,例如仅当有一些要读取的内容

This doesn't mean, however, that the master is immediately aware of changes on the slave end, e.g. a select() on the master will not return as soon as those changes happen, only when there is something to read

但是,在pty的本地标志词中设置EXTPROC之后-使用tcsetattr()-select() 将在从站状态更改后立即返回,然后可以检查从站termios-直接通过在父进程中保持打开状态的从属fd,或者至少在linux上,仅通过主端的tcgetattr()即可.

However, after setting EXTPROC in the pty's local flag word - using tcsetattr() - select() will return as soon as the slave state changes, and one can then inspect the slaves termios - either directly via the slave fd which we keep open in the parent process, or, on linux at least, simply by tcgetattr() on the master side.

请注意,EXTPROC会禁用pty驱动程序的某些部分,例如本地回显已关闭.

Note that EXTPROC disables certain parts of the pty driver, e.g. local echoing is turned off.

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

EXTPROC is not used a lot (here is a possible use case), not very portable and not documented at all (it shoud at least have been somewhere in the linux termios or tty_ioctl manpages). Looking at the linux kernel source drivers/tty/n_tty.c I conclude that any change in the slaves termios structure will make the select() on the master end return - but a tcsetattr() that doesn't change anything won't.

为响应塞巴斯蒂安·J.F.Sebastians的要求,我在下面提供了一个示例程序,该程序应明确说明如何在Linux计算机上以分组模式使用EXTRPOC:

in response to J.F. Sebastians's request below I give an example program that should make clear how to use EXTRPOC in packet mode on a linux machine:

/* 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同时构建).

In general, the master end of a pty need not be a tty (and have an associated termios structure), but under Linux, it is (with a shared termios: changes on one end will change both termios structures at the same time).

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

This means that we can modify the example program above and set EXTPROC on the master side, it won't make any difference.

据我所知,所有这些都没有记录在案,当然,甚至更不便于移植.

All of this is not documented as far as I can see, and even less portable, of course.

这篇关于当pty [伪终端]从属设备fd设置被"tcsetattr"改变时,将其设置为0. ,主机端如何立即捕获此事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆