我是
靠谱客的博主
花痴画板,这篇文章主要介绍
TTY终端的输入过程,现在分享给大家,希望可以做个参考。
TTY终端的输入过程
=================
1) 当用户按压键盘时, 键盘中断处理程序将经过转换的键盘功能码用tty_insert_flip_char()放入到当前打开终端的翻转缓冲区之中,
然后将缓冲区输出任务函数(flush_to_ldisc)添加到控制台任务队列(con_task_queue)并激活控制台软中断执行该任务函数. flush_to_ldisc()翻转读写缓冲区,
将缓冲区接收数据传递给tty终端规程的n_tty_receive_buf()接收函数, n_tty_receive_buf()处理输入字符, 将输出字符缓冲在终端的循环缓冲区(read_buf)之中.
用户通过tty规程的read_chan()读取read_buf中的字符. 当多个进程同时读取同一终端时, 使用tty->atomic_read信号灯来竞争读取权.
2) 每一打开的终端接口中包含终端的参数结构(termios), 当终端打开时, 它将继承终端驱动设备参数表中参数结构, 系统缺省的终端参数为tty_std_termios,
驱动设备的初始终端参数为init_termios. 终端参数可由用户通过ioctl()调整, 用来控制终端接口的行为. c_iflag描述对输入字符的识别模式,
c_oflag描述对输出字符的处理模式, c_cflag描述终端接口的控制模式, c_lflag描述字符处理过程中各种本地行为, 还有由19个字符组成的c_cc字符参数表,
描述各类控制字符以及辅助参数.
3) 当本地模式具有规范输入标志(ICANON)时, 输出数据按行拷贝给用户. 在接收到换行符(或者文件结束符c_cc[VEOF],行结束符c_cc[VEOL]和c_cc[VEOL2])之前,
可以使用编辑控制符完成简单的编辑. c_cc[VERASE]删除前一字符, c_cc[VKILL]删除整行, c_cc[VWERASE]删除前一单词.
4) 当本地模式具有回显标志(ECHO)时, 输入字符按一定的规则回显到输出设备上. 当本地模式具有信号标志(ISIG)时, 特定的输入字符可以在终端当前进程组中产生信号.
c_cc[VINTR]产生中断信号, c_cc[VQUIT]产生退出信息, c_cc[VSUSP]产生暂停信号. c_cc[VTIME]定义了用户读取数据的等待超时, 单位为0.1秒,
c_cc[VMIN]为所期望的字节数. 在非ICANON模式下, 如果在c_cc[VTIME]时间内接收到c_cc[VMIN]数量的字符, 读过程返回. c_cc[VSTOP]暂停驱动设备输出,
c_cc[VSTART]启动驱动设备输出.
5) 内核初始化结束后, 打开控制台终端设备/dev/console作为输入输出去运行/sbin/init. /dev/console的设备号是0x0501,
在打开时被定向到命令行(console=)指定的终端设备, 缺省情况下为/dev/tty1, 其设备号为0x0401. init程序完成用户初始化完成后启动若干个终端守护程序(getty).
getty在打开所守护的终端文件之前先使用setsid()创建会话组并成为会话组的首领进程(leader=1), 首领进程的会话号(session)和进程组号(pgrp)等于进程号(pid).
首领进程打开终端文件后成为终端的控制进程, 其tty指针指向该终端打开结构, 该终端也成为本次会话的控制终端,
其session号和pgrp号分别等于进程的session号和pgrp号. 当用户从终端登录后, 登录bash程序置换getty进程成为首领进程.
进程的会话号和组号随着进程的复制而传递, 子进程的首领标志复位.
bash在用execve()执行用户程序之前将用setpgid()为每一程序建立属于它自已的进程组(使进程组号等于进程号),
再用对终端的(TIOCSPGRP)设备控制将终端进程组号设为将该进程号, 使终端切换到新的进程组.
终端进程组以外的进程组如果进行读操作将在其进程组中生成SIGTTIN信号, 缺省的信号处理器使进程进入暂停.
; drivers/char/keyboard.c:
void put_queue(int ch)
{
wake_up(&keypress_wait);
if (tty) {
tty_insert_flip_char(tty, ch, 0);
con_schedule_flip(tty);
}
}
static void puts_queue(char *cp)
{
wake_up(&keypress_wait);
if (!tty)
return;
while (*cp) {
tty_insert_flip_char(tty, *cp, 0);
cp++;
}
con_schedule_flip(tty);
}
_INLINE_ void tty_insert_flip_char(struct tty_struct *tty,
unsigned char ch, char flag)
{
if (tty->flip.count < TTY_FLIPBUF_SIZE) {
tty->flip.count++;
*tty->flip.flag_buf_ptr++ = flag;
*tty->flip.char_buf_ptr++ = ch;
}
}
extern inline void con_schedule_flip(struct tty_struct *t)
{
queue_task(&t->flip.tqueue, &con_task_queue);
tasklet_schedule(&console_tasklet);
}
; drivers/char/tty_io.c:
/*
* When a break, frame error, or parity error happens, these codes are
* stuffed into the flags buffer.
*/
#define TTY_NORMAL 0
#define TTY_BREAK 1
#define TTY_FRAME 2
#define TTY_PARITY 3
#define TTY_OVERRUN 4
#define INTR_CHAR(tty) ((tty)->termios->c_cc[VINTR])
#define QUIT_CHAR(tty) ((tty)->termios->c_cc[VQUIT])
#define ERASE_CHAR(tty) ((tty)->termios->c_cc[VERASE])
#define KILL_CHAR(tty) ((tty)->termios->c_cc[VKILL])
#define EOF_CHAR(tty) ((tty)->termios->c_cc[VEOF])
#define TIME_CHAR(tty) ((tty)->termios->c_cc[VTIME])
#define MIN_CHAR(tty) ((tty)->termios->c_cc[VMIN])
#define SWTC_CHAR(tty) ((tty)->termios->c_cc[VSWTC])
#define START_CHAR(tty) ((tty)->termios->c_cc[VSTART])
#define STOP_CHAR(tty) ((tty)->termios->c_cc[VSTOP])
#define SUSP_CHAR(tty) ((tty)->termios->c_cc[VSUSP])
#define EOL_CHAR(tty) ((tty)->termios->c_cc[VEOL])
#define REPRINT_CHAR(tty) ((tty)->termios->c_cc[VREPRINT])
#define DISCARD_CHAR(tty) ((tty)->termios->c_cc[VDISCARD])
#define WERASE_CHAR(tty) ((tty)->termios->c_cc[VWERASE])
#define LNEXT_CHAR(tty) ((tty)->termios->c_cc[VLNEXT])
#define EOL2_CHAR(tty) ((tty)->termios->c_cc[VEOL2])
#define _I_FLAG(tty,f) ((tty)->termios->c_iflag & (f))
#define _O_FLAG(tty,f) ((tty)->termios->c_oflag & (f))
#define _C_FLAG(tty,f) ((tty)->termios->c_cflag & (f))
#define _L_FLAG(tty,f) ((tty)->termios->c_lflag & (f))
#define I_IGNBRK(tty) _I_FLAG((tty),IGNBRK)
#define I_BRKINT(tty) _I_FLAG((tty),BRKINT)
#define I_IGNPAR(tty) _I_FLAG((tty),IGNPAR)
#define I_PARMRK(tty) _I_FLAG((tty),PARMRK)
#define I_INPCK(tty) _I_FLAG((tty),INPCK)
#define I_ISTRIP(tty) _I_FLAG((tty),ISTRIP)
#define I_INLCR(tty) _I_FLAG((tty),INLCR)
#define I_IGNCR(tty) _I_FLAG((tty),IGNCR)
#define I_ICRNL(tty) _I_FLAG((tty),ICRNL)
#define I_IUCLC(tty) _I_FLAG((tty),IUCLC)
#define I_IXON(tty) _I_FLAG((tty),IXON)
#define I_IXANY(tty) _I_FLAG((tty),IXANY)
#define I_IXOFF(tty) _I_FLAG((tty),IXOFF)
#define I_IMAXBEL(tty) _I_FLAG((tty),IMAXBEL)
#define O_OPOST(tty) _O_FLAG((tty),OPOST)
#define O_OLCUC(tty) _O_FLAG((tty),OLCUC)
#define O_ONLCR(tty) _O_FLAG((tty),ONLCR)
#define O_OCRNL(tty) _O_FLAG((tty),OCRNL)
#define O_ONOCR(tty) _O_FLAG((tty),ONOCR)
#define O_ONLRET(tty) _O_FLAG((tty),ONLRET)
#define O_OFILL(tty) _O_FLAG((tty),OFILL)
#define O_OFDEL(tty) _O_FLAG((tty),OFDEL)
#define O_NLDLY(tty) _O_FLAG((tty),NLDLY)
#define O_CRDLY(tty) _O_FLAG((tty),CRDLY)
#define O_TABDLY(tty) _O_FLAG((tty),TABDLY)
#define O_BSDLY(tty) _O_FLAG((tty),BSDLY)
#define O_VTDLY(tty) _O_FLAG((tty),VTDLY)
#define O_FFDLY(tty) _O_FLAG((tty),FFDLY)
#define C_BAUD(tty) _C_FLAG((tty),CBAUD)
#define C_CSIZE(tty) _C_FLAG((tty),CSIZE)
#define C_CSTOPB(tty) _C_FLAG((tty),CSTOPB)
#define C_CREAD(tty) _C_FLAG((tty),CREAD)
#define C_PARENB(tty) _C_FLAG((tty),PARENB)
#define C_PARODD(tty) _C_FLAG((tty),PARODD)
#define C_HUPCL(tty) _C_FLAG((tty),HUPCL)
#define C_CLOCAL(tty) _C_FLAG((tty),CLOCAL)
#define C_CIBAUD(tty) _C_FLAG((tty),CIBAUD)
#define C_CRTSCTS(tty) _C_FLAG((tty),CRTSCTS)
#define L_ISIG(tty) _L_FLAG((tty),ISIG)
#define L_ICANON(tty) _L_FLAG((tty),ICANON)
#define L_XCASE(tty) _L_FLAG((tty),XCASE)
#define L_ECHO(tty) _L_FLAG((tty),ECHO)
#define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
#define L_ECHONL(tty) _L_FLAG((tty),ECHONL)
#define L_NOFLSH(tty) _L_FLAG((tty),NOFLSH)
#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP)
#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
#define L_ECHOPRT(tty) _L_FLAG((tty),ECHOPRT)
#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
#define L_FLUSHO(tty) _L_FLAG((tty),FLUSHO)
#define L_PENDIN(tty) _L_FLAG((tty),PENDIN)
#define L_IEXTEN(tty) _L_FLAG((tty),IEXTEN)
/* number of characters left in xmit buffer before select has we have room */
#define WAKEUP_CHARS 256
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
#define NCCS 19
struct termios {
tcflag_t c_iflag; /* input mode flags */
tcflag_t c_oflag; /* output mode flags */
tcflag_t c_cflag; /* control mode flags */
tcflag_t c_lflag; /* local mode flags */
cc_t c_line; /* line discipline */
cc_t c_cc[NCCS]; /* control characters */
};
/* intr=^C quit=^ erase=del kill=^U
eof=^D vtime= vmin=1 sxtc=
start=^Q stop=^S susp=^Z eol=
reprint=^R discard=^U werase=^W lnext=^V
eol2=
*/
#define INIT_C_CC "