Linux内核中如何实现I / O通道?


8

stdin,stdout,stderr是一些整数,它们会索引到一个数据结构中,从而“知道”该进程将使用哪些I / O通道。我了解此数据结构对于每个流程都是唯一的。I / O通道是否只是带有动态内存分配的某些数据阵列结构?


通过I / O通道表示流还是管道?同样,这可能因内核而异。您可能需要询问特定的内核。
13年

1
@strugee我在谈论Linux内核。我的意思是通过I / O通道进行流传输。这些流如何在Linux中实现?一些数组或什么?
KawaiKx

Answers:


14

在类似Unix的操作系统,标准输入,输出和错误流由文件描述符标识的012。在Linux上,这些proc文件在中的文件系统下可见/proc/[pid]/fs/{0,1,2}。这些文件实际上是指向目录下的终端设备的符号链接/dev/pts

伪终端(PTY)是一对虚拟设备,它们是伪终端主设备(PTM)和伪终端从设备(PTS)(统称为伪终端对),它们提供IPC通道,有点像程序之间的双向管道。连接到终端设备的驱动程序,以及使用伪终端向前一个程序发送输入和从前一个程序接收输入的驱动程序。

关键是伪终端从站就像普通终端一样出现,例如可以在非规范和规范模式之间切换(默认),在这种情况下,它解释某些输入字符,例如在产生中断字符SIGINT时产生信号 (通常是通过按键盘上的+ 键)写入到伪终端主机,或者在遇到文件结尾字符(通常由+ 生成)时使下一个主机返回。终端支持的其他操作是打开或关闭回显,设置前台进程组等。CtrlCread()0CtrlD

伪终端有多种用途:

  • 它们允许程序像ssh在通过网络连接的另一台主机上操作面向终端的程序。面向终端的程序可以是通常在交互式终端会话中运行的任何程序。此类程序的标准输入,输出和错误不能直接与套接字连接,因为套接字不支持上述与终端相关的功能。

  • 它们允许程序像expect通过脚本来驱动交互式的,面向终端的程序。

  • 终端仿真器使用它们xterm来提供与终端相关的功能。

  • 它们被程序使用,例如screen在多个进程之间复用单个物理终端。

  • 程序可以使用它们script来记录在Shell会话期间发生的所有输入和输出。

Linux中使用的Unix98风格的PTY设置如下:

  • 驱动程序在处打开伪终端主多路复用器dev/ptmx,在其上接收PTM的文件描述符,并在/dev/pts目录中创建PTS设备。通过打开获得的每个文件描述符/dev/ptmx都是一个具有自己关联的PTS的独立PTM。

  • 驱动程序编写调用fork()以创建一个子进程,该子进程依次执行以下步骤:

    • 子代呼叫setsid()开始一个新的会话,该子代为会话的领导者。这也导致孩子失去控制终端

    • 孩子继续打开与驱动程序创建的PTM相对应的PTS设备。由于孩子是会话领导者,但没有控制终端,因此PTS成为孩子的控制终端。

    • 子级用于dup()在其标准输入,输出和错误上复制从属设备的文件描述符。

    • 最后,孩子调用exec()以启动将要连接到伪终端设备的面向终端的程序。

此时,驱动程序写入PTM的所有内容都会显示为PTS上面向终端程序的输入,反之亦然。

在规范模式下运行时,PTS的输入会逐行缓冲。换句话说,就像常规终端一样,仅当将换行符写入PTM时,从PTS读取的程序才接收一行输入。当缓冲容量用完时,write()将阻止进一步的调用,直到消耗了一些输入。

在Linux内核,文件相关的系统调用open()read()write() stat()等在虚拟文件系统(VFS)层,它提供一个统一的文件系统接口为用户空间程序被实现。VFS允许不同的文件系统实现在内核中共存。当用户空间程序调用上述系统调用时,VFS会将调用重定向到适当的文件系统实现。

下面的PTS设备/dev/pts由中devpts定义的文件系统实现管理/fs/devpts/inode.c,而提供Unix98风格ptmx设备的TTY驱动程序在中定义drivers/tty/pty.c

TTY设备和TTY 线路规范(例如伪终端)之间的缓冲提供了为每个tty设备维护的缓冲区结构,该结构在include/linux/tty.h

在内核版本3.7之前,该缓冲区是翻转缓冲区

#define TTY_FLIPBUF_SIZE 512

struct tty_flip_buffer {
        struct tq_struct tqueue;
        struct semaphore pty_sem;
        char             *char_buf_ptr;
        unsigned char    *flag_buf_ptr;
        int              count;
        int              buf_num;
        unsigned char    char_buf[2*TTY_FLIPBUF_SIZE];
        char             flag_buf[2*TTY_FLIPBUF_SIZE];
        unsigned char    slop[4];
};

该结构包含分为两个相等大小的缓冲区的存储。缓冲区编号为的0前半部分char_buf/flag_buf1后半部分。驱动程序将数据存储到由标识的缓冲区中buf_num。另一个缓冲区可以刷新到线路规则。

通过buf_num0和之间切换来“翻转”缓冲区1。当buf_num改变,char_buf_ptrflag_buf_ptr 设置为查明的缓冲区的开始buf_num,并count设置为0

从内核版本3.7开始,TTY翻转缓冲区已替换为通过kmalloc()按环组织的对象分配的对象。在正常情况下,以IRQ驱动的串行端口以典型速度运行时,其行为与旧的翻转缓冲区几乎相同。最终分配了两个缓冲区,它们之间的内核循环像以前一样。但是,当存在延迟或速度增加时,新的缓冲实现会更好,因为缓冲池可以增加一点。


如此困难的答案很难得到。
étale-上同调

-1

在这三个手册中的任何一个的手册页中,它解释了答案:

   Under  normal circumstances every UNIX program has three streams opened
   for it when it starts up, one for input, one for output,  and  one  for
   printing diagnostic or error messages.  These are typically attached to
   the user's terminal but might instead  refer  to  files  or
   other  devices,  depending  on what the parent process chose to set up.

   The input stream is referred to as "standard input"; the output  stream
   is  referred  to as "standard output"; and the error stream is referred
   to as "standard error".  These terms are abbreviated to form  the  sym-
   bols used to refer to these files, namely stdin, stdout, and stderr.

   Each  of these symbols is a stdio(3) macro of type pointer to FILE, and
   can be used with functions like fprintf(3) or fread(3).

   Since FILEs are a buffering wrapper around UNIX file  descriptors,  the
   same  underlying  files  may  also  be accessed using the raw UNIX file
   interface, that is, the functions like read(2) and lseek(2).

   On program startup, the integer file descriptors  associated  with  the
   streams  stdin,  stdout, and stderr are 0, 1, and 2, respectively.  The
   preprocessor symbols STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO are
   defined  with  these values in <unistd.h>.

这个答案描述的实施stdinstdoutstderr从视C库点,但问题是明确有关内核执行。我试图在回答中解释内核的观点。
Thomas Nyman 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.