📄 tty_io.c
字号:
// 如果该字符是停止字符(^Q),则复位tty 停止标志,继续处理其它字符。 if (c == START_CHAR (tty)) { tty->stopped = 0; continue; } }// 若输入模式标志集中ISIG 标志置位,则在收到INTR、QUIT、SUSP 或DSUSP 字符时,需要为进程// 产生相应的信号。 if (L_ISIG (tty)) {// 如果该字符是键盘中断符(^C),则向当前进程发送键盘中断信号,并继续处理下一字符。 if (c == INTR_CHAR (tty)) { tty_intr (tty, INTMASK); continue; }// 如果该字符是键盘中断符(^\),则向当前进程发送键盘退出信号,并继续处理下一字符。 if (c == QUIT_CHAR (tty)) { tty_intr (tty, QUITMASK); continue; } }// 如果该字符是换行符NL(10),或者是文件结束符EOF(^D),辅助缓冲队列字符数加1。[??] if (c == 10 || c == EOF_CHAR (tty)) tty->secondary.data++;// 如果本地模式标志集中回显标志ECHO 置位,那么,如果字符是换行符NL(10),则将换行符NL(10)// 和回车符CR(13)放入tty 写队列缓冲区中;如果字符是控制字符(字符值<32)并且回显控制字符标志// ECHOCTL 置位,则将字符'^'和字符c+64 放入tty 写队列中(也即会显示^C、^H 等);否则将该字符// 直接放入tty 写缓冲队列中。最后调用该tty 的写操作函数。 if (L_ECHO (tty)) { if (c == 10) { PUTCH (10, tty->write_q); PUTCH (13, tty->write_q); } else if (c < 32) { if (L_ECHOCTL (tty)) { PUTCH ('^', tty->write_q); PUTCH (c + 64, tty->write_q); } } else PUTCH (c, tty->write_q); tty->write (tty); }// 将该字符放入辅助队列中。 PUTCH (c, tty->secondary); }// 唤醒等待该辅助缓冲队列的进程(如果有的话)。 wake_up (&tty->secondary.proc_list);}//// tty 读函数。// 参数:channel - 子设备号;buf - 缓冲区指针;nr - 欲读字节数。// 返回已读字节数。inttty_read (unsigned channel, char *buf, int nr){ struct tty_struct *tty; char c, *b = buf; int minimum, time, flag = 0; long oldalarm;// 本版本linux 内核的终端只有3 个子设备,分别是控制台(0)、串口终端1(1)和串口终端2(2)。// 所以任何大于2 的子设备号都是非法的。写的字节数当然也不能小于0 的。 if (channel > 2 || nr < 0) return -1;// tty 指针指向子设备号对应ttb_table 表中的tty 结构。 tty = &tty_table[channel];// 下面首先保存进程原定时值,然后根据控制字符VTIME 和VMIN 设置读字符操作的超时定时值。// 在非规范模式下,这两个值是超时定时值。MIN 表示为了满足读操作,需要读取的最少字符数。// TIME 是一个十分之一秒计数的计时值。// 首先取进程中的(报警)定时值(滴答数)。 oldalarm = current->alarm;// 并设置读操作超时定时值time 和需要最少读取的字符个数minimum。 time = 10L * tty->termios.c_cc[VTIME]; minimum = tty->termios.c_cc[VMIN];// 如果设置了读超时定时值time 但没有设置最少读取个数minimum,那么在读到至少一个字符或者// 定时超时后读操作将立刻返回。所以这里置minimum=1。 if (time && !minimum) { minimum = 1;// 如果进程原定时值是0 或者time+当前系统时间值小于进程原定时值的话,则置重新设置进程定时// 值为time+当前系统时间,并置flag 标志。 if (flag = (!oldalarm || time + jiffies < oldalarm)) current->alarm = time + jiffies; }// 如果设置的最少读取字符数>欲读的字符数,则令其等于此次欲读取的字符数。 if (minimum > nr) minimum = nr;// 当欲读的字节数>0,则循环执行以下操作。 while (nr > 0) {// 如果flag 不为0(即进程原定时值是0 或者time+当前系统时间值小于进程原定时值)并且进程有定// 时信号SIGALRM,则复位进程的定时信号并中断循环。 if (flag && (current->signal & ALRMMASK)) { current->signal &= ~ALRMMASK; break; }// 如果当前进程有信号要处理,则退出,返回0。 if (current->signal) break;// 如果辅助缓冲队列(规范模式队列)为空,或者设置了规范模式标志并且辅助队列中字符数为0 以及// 辅助模式缓冲队列空闲空间>20,则进入可中断睡眠状态,返回后继续处理。 if (EMPTY (tty->secondary) || (L_CANON (tty) && !tty->secondary.data && LEFT (tty->secondary) > 20)) { sleep_if_empty (&tty->secondary); continue; }// 执行以下操作,直到nr=0 或者辅助缓冲队列为空。 do {// 取辅助缓冲队列字符c。 GETCH (tty->secondary, c);// 如果该字符是文件结束符(^D)或者是换行符NL(10),则辅助缓冲队列字符数减1。 if (c == EOF_CHAR (tty) || c == 10) tty->secondary.data--;// 如果该字符是文件结束符(^D)并且规范模式标志置位,则返回已读字符数,并退出。 if (c == EOF_CHAR (tty) && L_CANON (tty)) return (b - buf);// 否则将该字符放入用户数据段缓冲区buf 中,欲读字符数减1,如果欲读字符数已为0,则中断循环。 else { put_fs_byte (c, b++); if (!--nr) break; } } while (nr > 0 && !EMPTY (tty->secondary));// 如果超时定时值time 不为0 并且规范模式标志没有置位(非规范模式),那么: if (time && !L_CANON (tty))// 如果进程原定时值是0 或者time+当前系统时间值小于进程原定时值的话,则置重新设置进程定时值// 为time+当前系统时间,并置flag 标志。否则让进程的定时值等于进程原定时值。 if (flag = (!oldalarm || time + jiffies < oldalarm)) current->alarm = time + jiffies; else current->alarm = oldalarm;// 如果规范模式标志置位,那么若没有读到1 个字符则中断循环。否则若已读取数大于或等于最少要// 求读取的字符数,则也中断循环。 if (L_CANON (tty)) { if (b - buf) break; } else if (b - buf >= minimum) break; }// 让进程的定时值等于进程原定时值。 current->alarm = oldalarm;// 如果进程有信号并且没有读取任何字符,则返回出错号(超时)。 if (current->signal && !(b - buf)) return -EINTR; return (b - buf); // 返回已读取的字符数。}//// tty 写函数。// 参数:channel - 子设备号;buf - 缓冲区指针;nr - 写字节数。// 返回已写字节数。inttty_write (unsigned channel, char *buf, int nr){ static cr_flag = 0; struct tty_struct *tty; char c, *b = buf;// 本版本linux 内核的终端只有3 个子设备,分别是控制台(0)、串口终端1(1)和串口终端2(2)。// 所以任何大于2 的子设备号都是非法的。写的字节数当然也不能小于0 的。 if (channel > 2 || nr < 0) return -1;// tty 指针指向子设备号对应ttb_table 表中的tty 结构。 tty = channel + tty_table;// 字符设备是一个一个字符进行处理的,所以这里对于nr 大于0 时对每个字符进行循环处理。 while (nr > 0) {// 如果此时tty 的写队列已满,则当前进程进入可中断的睡眠状态。 sleep_if_full (&tty->write_q);// 如果当前进程有信号要处理,则退出,返回0。 if (current->signal) break;// 当要写的字节数>0 并且tty 的写队列不满时,循环执行以下操作。 while (nr > 0 && !FULL (tty->write_q)) {// 从用户数据段内存中取一字节c。 c = get_fs_byte (b);// 如果终端输出模式标志集中的执行输出处理标志OPOST 置位,则执行下列输出时处理过程。 if (O_POST (tty)) {// 如果该字符是回车符'\r'(CR,13)并且回车符转换行符标志OCRNL 置位,则将该字符换成换行符// '\n'(NL,10);否则如果该字符是换行符'\n'(NL,10)并且换行转回车功能标志ONLRET 置位的话,// 则将该字符换成回车符'\r'(CR,13)。 if (c == '\r' && O_CRNL (tty)) c = '\n'; else if (c == '\n' && O_NLRET (tty)) c = '\r';// 如果该字符是换行符'\n'并且回车标志cr_flag 没有置位,换行转回车-换行标志ONLCR 置位的话,// 则将cr_flag 置位,并将一回车符放入写队列中。然后继续处理下一个字符。 if (c == '\n' && !cr_flag && O_NLCR (tty)) { cr_flag = 1; PUTCH (13, tty->write_q); continue; }// 如果小写转大写标志OLCUC 置位的话,就将该字符转成大写字符。 if (O_LCUC (tty)) c = toupper (c); }// 用户数据缓冲指针b 前进1 字节;欲写字节数减1 字节;复位cr_flag 标志,并将该字节放入tty// 写队列中。 b++; nr--; cr_flag = 0; PUTCH (c, tty->write_q); }// 若字节全部写完,或者写队列已满,则程序执行到这里。调用对应tty 的写函数,若还有字节要写,// 则等待写队列不满,所以调用调度程序,先去执行其它任务。 tty->write (tty); if (nr > 0) schedule (); } return (b - buf); // 返回写入的字节数。}/** Jeh, sometimes I really like the 386.* This routine is called from an interrupt,* and there should be absolutely no problem* with sleeping even in an interrupt (I hope).* Of course, if somebody proves me wrong, I'll* hate intel for all time :-). We'll have to* be careful and see to reinstating the interrupt* chips before calling this, though.** I don't think we sleep here under normal circumstances* anyway, which is good, as the task sleeping might be* totally innocent.*//** 呵,有时我是真得很喜欢386。该子程序是从一个中断处理程序中调用的,即使在* 中断处理程序中睡眠也应该绝对没有问题(我希望如此)。当然,如果有人证明我是* 错的,那么我将憎恨intel 一辈子?。但是我们必须小心,在调用该子程序之前需* 要恢复中断。** 我不认为在通常环境下会处在这里睡眠,这样很好,因为任务睡眠是完全任意的。*///// tty 中断处理调用函数 - 执行tty 中断处理。// 参数:tty - 指定的tty 终端号(0,1 或2)。// 将指定tty 终端队列缓冲区中的字符复制成规范(熟)模式字符并存放在辅助队列(规范模式队列)中。// 在串口读字符中断(rs_io.s, 109)和键盘中断(kerboard.S, 69)中调用。voiddo_tty_interrupt (int tty){ copy_to_cooked (tty_table + tty);}//// 字符设备初始化函数。空,为以后扩展做准备。voidchr_dev_init (void){}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -