奇思妙想 · 2024年 9月 14日 0

Ctrl + D是如何与内核文件结束符对应的?

23 次浏览

*nix系统的终端一般会输入Ctrl + D代表输入流结束,Linux和macOS均是如此,尽管Windows用Ctrl + Z,仅仅是外部按键表现,最终目的是一样的。如下以Linux 6.11为例讲解。

  • 每开启一个终端会开启一个terminal设备,以tty为例,对应于内核的tty_struct (include\linux\tty.h).
  • tty默认配置会定义常见控制按键映射关系:
    #define INIT_C_CC { \
    [VINTR] = 'C'-0x40, \
    [VQUIT] = '\\'-0x40, \
    [VERASE] = '\177', \
    [VKILL] = 'U'-0x40, \
    [VEOF] = 'D'-0x40, \
    [VSTART] = 'Q'-0x40, \
    [VSTOP] = 'S'-0x40, \
    [VSUSP] = 'Z'-0x40, \
    [VREPRINT] = 'R'-0x40, \
    [VDISCARD] = 'O'-0x40, \
    [VWERASE] = 'W'-0x40, \
    [VLNEXT] = 'V'-0x40, \
    INIT_C_CC_VDSUSP_EXTRA \
    [VMIN] = 1 }

    上面的VEOF代表文件结束符对应的按键数值是4.
  • 如上INIT_C_CC会被带入kernel tty标准属性设定 tty_io.c (drivers/tty)
    struct ktermios tty_std_termios = { /* for the benefit of tty drivers /
    .c_iflag = ICRNL | IXON,
    .c_oflag = OPOST | ONLCR,
    .c_cflag = B38400 | CS8 | CREAD | HUPCL,
    .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN,
    .c_cc = INIT_C_CC,
    .c_ispeed = 38400,
    .c_ospeed = 38400,
    / .c_line = N_TTY, */
    };
  • 用户层可通过tcgetattr函数获取对应终端tty (struct termios)的c_cc[VEOF]信息,一般而言默认为0x4, 对应于ASCII EOT (End Of Transmission).
    - 也可用stty -a命令获取当前tty的设定:
    speed 38400 baud; rows 17; columns 198; line = 0;
    intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = M-^?;
  • 综上,Ctrl + D触发按键4,内核根据它注册的EOF传递给上层EOF讯息.