N_TTY

默认(和回退)TTY 行规程。它尝试按照 POSIX 处理字符。

外部函数

void n_tty_inherit_ops(struct tty_ldisc_ops *ops)

继承 N_TTY 方法

参数

struct tty_ldisc_ops *ops

struct tty_ldisc_ops 用于保存 N_TTY 方法的位置

使“子类”行规程能够“继承”N_TTY 方法。

内部函数

void n_tty_kick_worker(const struct tty_struct *tty)

启动输入工作线程(如果需要)

参数

const struct tty_struct *tty

终端

描述

如果翻转缓冲区工作可能已停止,则重新调度它。

锁定
  • 调用者持有独占 termios_rwsem,或者

  • n_tty_read()/消费者路径

    持有非独占 termios_rwsem

void n_tty_write_wakeup(struct tty_struct *tty)

异步 I/O 通知器

参数

struct tty_struct *tty

tty 设备

描述

对于 ptys、串行驱动程序等是必需的,因为附加到主设备并依赖于异步 IO 的进程必须被唤醒。

void put_tty_queue(u8 c, struct n_tty_data *ldata)

将字符添加到 tty

参数

u8 c

字符

struct n_tty_data *ldata

n_tty 数据

描述

将字符添加到 tty read_buf 队列。

锁定
  • n_tty_receive_buf()/生产者路径

    调用者持有非独占 termios_rwsem

void reset_buffer_flags(struct n_tty_data *ldata)

重置缓冲区状态

参数

struct n_tty_data *ldata

要重置的行规程数据

描述

重置读取缓冲区计数器并清除标志。从 n_tty_open()n_tty_flush_buffer() 调用。

锁定
  • 调用者持有独占 termios_rwsem,或者

  • (不需要锁定)

void n_tty_flush_buffer(struct tty_struct *tty)

清除输入队列

参数

struct tty_struct *tty

终端设备

描述

刷新输入缓冲区。当 tty 层想要刷新缓冲区时(例如在挂断时)或当 N_TTY 行规程内部必须清除挂起队列时(例如某些信号)调用。

持有 termios_rwsem 以在缓冲区索引重置时排除生产者/消费者。

锁定:ctrl.lock,独占 termios_rwsem

int is_utf8_continuation(u8 c)

utf8 多字节检查

参数

u8 c

要检查的字节

返回

如果 utf8 字符 c 是一个多字节延续字符,则返回 true。我们使用它来正确计算打印时字符的屏幕大小。

int is_continuation(u8 c, const struct tty_struct *tty)

多字节检查

参数

u8 c

要检查的字节

const struct tty_struct *tty

终端设备

返回

如果 utf8 字符 c 是一个多字节延续字符且终端处于 unicode 模式,则返回 true。

int do_output_char(u8 c, struct tty_struct *tty, int space)

输出一个字符

参数

u8 c

字符(或部分 unicode 符号)

struct tty_struct *tty

终端设备

int space

tty 驱动程序写入缓冲区中的可用空间

描述

这是一个辅助函数,用于处理一个输出字符(包括 TAB、CR、LF 等特殊字符),进行 OPOST 处理并将结果放入 tty 驱动程序的写入缓冲区。

请注意,Linux 当前忽略 TABDLY、CRDLY、VTDLY、FFDLY 和 NLDLY。它们在当今世界根本不相关。如果您需要它们,请在此处添加它们。

锁定:应在 output_lock 下调用以保护列状态和缓冲区中剩余的空间。

返回

已使用的缓冲区空间字节数,如果空间不足,则为 -1。

int process_output(u8 c, struct tty_struct *tty)

输出后处理器

参数

u8 c

字符(或部分 unicode 符号)

struct tty_struct *tty

终端设备

描述

使用 OPOST 处理输出一个字符。

锁定: output_lock 用于保护列状态和剩余空间(此外,此函数在 tty 层写锁下被 n_tty_write() 调用)。

返回

当输出设备已满并且必须重试字符时返回 -1。

ssize_t process_output_block(struct tty_struct *tty, const u8 *buf, unsigned int nr)

块后处理器

参数

struct tty_struct *tty

终端设备

const u8 *buf

字符缓冲区

unsigned int nr

要输出的字节数

描述

使用 OPOST 处理输出一个字符块。

此路径用于加快块控制台写入,以及处理块输出数据等情况。它只处理通常遇到的简单情况,并帮助为控制台驱动程序生成符号块,从而提高性能。

锁定: output_lock 用于保护列状态和剩余空间(此外,此函数在 tty 层写锁下被 n_tty_write() 调用)。

返回

输出的字符数。

size_t __process_echoes(struct tty_struct *tty)

写入待处理的回显字符

参数

struct tty_struct *tty

终端设备

描述

将先前缓冲的回显(和其他 ldisc 生成的)字符写入 tty。

ldisc 生成的字符(包括回显)需要缓冲,因为在大量程序输出期间驱动程序的写入缓冲区可能会填满。在这些情况下,直接回显到驱动程序通常会失败,导致字符丢失和 ldisc 状态信息不匹配。

由于 ldisc 状态必须表示写入时实际发送到驱动程序的字符,因此诸如列状态的某些更改等操作也会保存在缓冲区中并在此处执行。

使用循环 fifo 缓冲区,以便优先处理最近的字符。此外,当使用前缀 “^” 回显控制字符时,该对被原子处理,因此不会分离。

锁定:调用者必须持有 output_lock

void add_echo_byte(u8 c, struct n_tty_data *ldata)

向回显缓冲区添加一个字节

参数

u8 c

要回显的 Unicode 字节

struct n_tty_data *ldata

n_tty 数据

描述

向回显缓冲区添加一个字符或操作字节。

void echo_move_back_col(struct n_tty_data *ldata)

添加一个操作以向后移动一列

参数

struct n_tty_data *ldata

n_tty 数据

描述

向回显缓冲区添加一个操作以向后移动一列。

void echo_set_canon_col(struct n_tty_data *ldata)

添加一个操作以设置规范列

参数

struct n_tty_data *ldata

n_tty 数据

描述

向回显缓冲区添加一个操作以将规范列设置为当前列。

void echo_erase_tab(unsigned int num_chars, int after_tab, struct n_tty_data *ldata)

添加一个操作以删除制表符

参数

unsigned int num_chars

已使用的字符列数

int after_tab

如果 num_chars 从先前制表符之后开始,则为 true

struct n_tty_data *ldata

n_tty 数据

描述

向回显缓冲区添加一个操作以删除制表符。

由擦除器函数调用,该函数知道自先前制表符或输入开始以来已使用了多少个字符列。此信息稍后将与规范列(如果适用)一起使用,以返回正确的列数。

void echo_char_raw(u8 c, struct n_tty_data *ldata)

原始回显一个字符

参数

u8 c

要回显的 Unicode 字节

struct n_tty_data *ldata

行规程数据

描述

将用户输入回显到屏幕上。仅当 L_ECHO(tty) 为 true 时才必须调用此函数。从 tty_driver.receive_buf() 路径调用。

此变体不特别处理控制字符。

void echo_char(u8 c, const struct tty_struct *tty)

回显一个字符

参数

u8 c

要回显的 Unicode 字节

const struct tty_struct *tty

终端设备

描述

将用户输入回显到屏幕上。仅当 L_ECHO(tty) 为 true 时才必须调用此函数。从 tty_driver.receive_buf() 路径调用。

此变体标记控制字符,回显为 “^X”(其中 X 是表示控制字符的字母)。

void finish_erasing(struct n_tty_data *ldata)

完成擦除

参数

struct n_tty_data *ldata

n_tty 数据

void eraser(u8 c, const struct tty_struct *tty)

处理擦除功能

参数

u8 c

字符输入

const struct tty_struct *tty

终端设备

描述

当驱动程序层流中存在擦除字符时,执行擦除和必要的输出。处理 UTF-8 多字节符号的复杂性。

锁定: n_tty_receive_buf()/生产者路径

调用者持有非独占 termios_rwsem

void isig(int sig, struct tty_struct *tty)

处理 ISIG 选项

参数

int sig

信号

struct tty_struct *tty

终端

描述

当由于终端输入而发送信号时调用。从 tty_driver.receive_buf() 路径调用,因此是序列化的。

如果 !NOFLSH,则执行输入和输出刷新。在此上下文中,回显缓冲区是“输出”。首先处理信号,以通知任何当前的读取器或写入器停止并退出其 i/o 循环。

锁定: ctrl.lock

void n_tty_receive_break(struct tty_struct *tty)

处理中断

参数

struct tty_struct *tty

终端

描述

在传入的比特流中已命中 RS232 中断事件。这可能会根据 termios 设置导致各种事件。

锁定: n_tty_receive_buf()/生产者路径

调用者持有非排他的 termios_rwsem

注意

如果刷新输入缓冲区,可能会获取排他的 termios_rwsem

void n_tty_receive_overrun(const struct tty_struct *tty)

处理溢出报告

参数

const struct tty_struct *tty

终端

描述

数据到达速度超过了我们的处理速度。虽然 tty 驱动程序已标记此问题,但丢失的数据位已永远消失。

从 receive_buf 路径调用,因此是单线程的。由于 num_overrun 和 overrun_time 是函数私有的,因此不需要加锁。

void n_tty_receive_parity_error(const struct tty_struct *tty, u8 c)

错误通知器

参数

const struct tty_struct *tty

终端设备

u8 c

字符

描述

处理奇偶校验错误,并在必要时将正确的数据排队,以指示错误情况。

锁定: n_tty_receive_buf()/生产者路径

调用者持有非独占 termios_rwsem

bool n_tty_receive_char_flow_ctrl(struct tty_struct *tty, u8 c, bool lookahead_done)

接收流控制字符

参数

struct tty_struct *tty

终端设备

u8 c

字符

bool lookahead_done

前瞻已处理此字符

描述

接收并处理流控制字符操作。

如果用于流控制字符的前瞻已经提前处理了正常接收中的字符,则在正常接收期间会跳过这些操作。

如果 c 被用作流控制字符,则返回 true,该字符不得被视为普通字符。

void n_tty_receive_char(struct tty_struct *tty, u8 c)

执行处理

参数

struct tty_struct *tty

终端设备

u8 c

字符

描述

处理从驱动程序接收的单个输入字符。根据上述驱动程序的规则,这是相对于自身串行化的。

锁定: n_tty_receive_buf()/生产者路径

调用者持有非独占的 termios_rwsem,如果规范模式处于活动状态,则发布 canon_head

size_t n_tty_receive_buf_common(struct tty_struct *tty, const u8 *cp, const u8 *fp, size_t count, bool flow)

处理输入

参数

struct tty_struct *tty

接收输入的设备

const u8 *cp

输入字符

const u8 *fp

每个字符的标志(如果为 NULL,则所有字符均为 TTY_NORMAL

size_t count

cp 中输入字符的数量

bool flow

启用流控制

描述

当接收到字符块时,由终端驱动程序调用。此函数必须从软上下文中调用,而不是从中断上下文中调用。驱动程序负责一次一个地按顺序进行调用(或使用 flush_to_ldisc())。

在规范模式下,最大行长度为 4096 个字符(包括行终止符);长于 4096 个字符的行将被截断。在 4095 个字符之后,输入数据仍会被处理,但不存储。溢出处理确保 tty 始终可以接收更多输入,直到至少可以读取一行。

在非规范模式下,读取缓冲区仅接受 4095 个字符;如果输入模式切换为规范模式,则这为换行符提供了必要的空间。

请注意,在非规范模式下,读取缓冲区可能包含 4096 个字符:当模式切换为非规范模式时,读取缓冲区可能已经包含最大规范行 4096 个字符。

锁定: n_tty_receive_buf()/生产者路径

声明非独占的 termios_rwsem 发布 commit_head 或 canon_head

返回

来自 cp 的已处理的输入字符数。

void n_tty_set_termios(struct tty_struct *tty, const struct ktermios *old)

termios 数据已更改

参数

struct tty_struct *tty

终端

const struct ktermios *old

以前的数据

描述

当用户更改 termios 标志时,由 tty 层调用,以便线路规程可以提前计划。此函数不能休眠,并且受到 tty 层的保护,防止重入。用户保证在关闭 ldisc 时不会重入或正在进行此函数。

锁定:调用方持有 tty->termios_rwsem

void n_tty_close(struct tty_struct *tty)

关闭此 tty 的 ldisc

参数

struct tty_struct *tty

设备

描述

当此线路规程因关闭或规程更改而关闭时,从终端层调用。在其他 ldisc 方法正在进行时,不会调用该函数。

int n_tty_open(struct tty_struct *tty)

打开 ldisc

参数

struct tty_struct *tty

要打开的终端

描述

当此线路规程附加到终端设备时调用。可以休眠。调用是串行化的,因此不会并行发生其他事件。在关闭之前不会发生进一步的打开。

bool copy_from_read_buf(const struct tty_struct *tty, u8 **kbp, size_t *nr)

直接复制读取数据

参数

const struct tty_struct *tty

终端设备

u8 **kbp

数据

size_t *nr

数据大小

描述

加速 n_tty_read() 的辅助函数。仅当 ICANON 关闭时才调用此函数;它直接从 tty 队列复制字符。

锁定
  • ldata->atomic_read_lock sem 下调用

  • n_tty_read()/消费者路径

    调用方持有非独占的 termios_rwsem;发布 read_tail

返回

如果成功复制数据,则为 true,但仍有更多数据要获取。

bool canon_copy_from_read_buf(const struct tty_struct *tty, u8 **kbp, size_t *nr)

以规范模式复制读取数据

参数

const struct tty_struct *tty

终端设备

u8 **kbp

数据

size_t *nr

数据大小

描述

n_tty_read() 的辅助函数。它仅在 ICANON 打开时调用;它将一行输入(包括行分隔符)复制到结果缓冲区中。

锁定
  • atomic_read_lock 互斥锁下调用

  • n_tty_read()/消费者路径

    调用方持有非独占的 termios_rwsem;发布 read_tail

注意

当 termios 从非规范模式更改为规范模式,并且读取缓冲区包含数据时,n_tty_set_termios() 会模拟一个 EOF 推送(就像输入了 C-d 一样),_不带_ 缓冲区中的 DISABLED_CHAR。这会导致已作为输入处理的数据立即可用作输入,即使尚未收到换行符。

int job_control(struct tty_struct *tty, struct file *file)

检查作业控制

参数

struct tty_struct *tty

tty

struct file *file

文件句柄

描述

在此 file/tty 描述符上执行作业控制管理检查,如果合适,则发送任何需要的信号,如果应采取操作,则返回负错误代码。

锁定
  • 重定向写入测试是安全的

  • current->signal->tty 检查是安全的

  • ctrl.lock 安全地引用 tty->ctrl.pgrp

ssize_t n_tty_read(struct tty_struct *tty, struct file *file, u8 *kbuf, size_t nr, void **cookie, unsigned long offset)

tty 的读取函数

参数

struct tty_struct *tty

tty 设备

struct file *file

文件对象

u8 *kbuf

内核空间缓冲区指针

size_t nr

I/O 大小

void **cookie

如果非 NULL,则这是一个连续读取

unsigned long offset

从何处继续读取(在 n_tty 中未使用)

描述

为行规程执行读取。 我们保证行规程不会在我们之下关闭,但我们可能会有多个并行读取器,并且必须自行处理。 我们也可能会收到挂断。 始终在用户上下文中调用,可能会休眠。

此代码必须确保永远不会在挂断时休眠。

锁定:n_tty_read() /消费者路径

声明非独占 termios_rwsem;发布 read_tail

ssize_t n_tty_write(struct tty_struct *tty, struct file *file, const u8 *buf, size_t nr)

tty 的写入函数

参数

struct tty_struct *tty

tty 设备

struct file *file

文件对象

const u8 *buf

用户空间缓冲区指针

size_t nr

I/O 大小

描述

终端设备的写入函数。 这与其他写入调用者是串行化的,但与 termios 更改、读取和其他此类事件不是串行化的。 由于接收代码将回显字符,从而调用驱动程序写入方法,因此在 此处调用的输出处理函数以及回显处理函数中使用 output_lock 来保护列状态和缓冲区中剩余的空间。

此代码必须确保永远不会在挂断时休眠。

锁定:output_lock 用于保护列状态和剩余空间

(请注意,process_output*() 函数本身会获取此锁)

__poll_t n_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)

N_TTY 的轮询方法

参数

struct tty_struct *tty

终端设备

struct file *file

访问它的文件

poll_table *wait

轮询表

描述

当要求行规程轮询 () 数据或特殊事件时调用。 此代码与其他事件(保存打开/关闭)不是串行化的。

此代码必须确保永远不会在挂断时休眠。

锁定:在没有持有内核锁的情况下调用——没问题。