TTY 内部原理

Kopen

这些函数用于从内核空间打开 TTY

void tty_kclose(struct tty_struct *tty)

关闭由 tty_kopen 打开的 tty

参数

struct tty_struct *tty

tty 设备

描述

执行释放和释放 tty 设备的最后步骤。它与tty_release_struct()相同,只是它还会重置 **tty->port** 上的 TTY_PORT_KOPENED 标志。

struct tty_struct *tty_kopen_exclusive(dev_t device)

为内核打开 tty 设备

参数

dev_t device

要打开的设备的 dev_t

描述

为内核独占打开 tty。执行驱动程序查找,确保它尚未打开,并执行首次 tty 初始化。

声明全局 tty_mutex 以序列化
  • 并发首次 tty 初始化

  • 并发 tty 驱动程序删除和查找

  • 从驱动程序表中并发删除 tty

返回

锁定的初始化tty_struct

struct tty_struct *tty_kopen_shared(dev_t device)

打开 tty 设备以供内核共享使用

参数

dev_t device

要打开的设备的 dev_t

描述

打开一个已经存在的 tty 以供内核使用。与上面的tty_kopen_exclusive()相比,它不保证是唯一的用户。

锁定:与上面的 tty_kopen() 相同。


导出的内部函数

int tty_dev_name_to_number(const char *name, dev_t *number)

返回设备名称的 dev_t

参数

const char *name

/dev 下的设备的用户空间名称

dev_t *number

指向此函数将填充的 dev_t 的指针

描述

此函数将 ttyS0 或 ttyUSB1 等设备名称转换为 (4, 64) 或 (188, 1) 等 dev_t。如果没有注册相应的驱动程序,则该函数返回 -ENODEV

锁定:这会获取 tty_mutex 以保护 tty_drivers 列表免受

在我们遍历它时被修改,并确保在退出之前释放它。

void tty_release_struct(struct tty_struct *tty, int idx)

释放 tty 结构

参数

struct tty_struct *tty

tty 设备

int idx

tty 的索引

描述

执行释放和释放 tty 设备的最后步骤。它大致是tty_init_dev()的反向操作。

int tty_get_icount(struct tty_struct *tty, struct serial_icounter_struct *icount)

获取 tty 统计信息

参数

struct tty_struct *tty

tty 设备

struct serial_icounter_struct *icount

输出参数

描述

获取 **tty** 的 icount 统计信息的副本。

锁定:无(取决于驱动程序)


内部函数

void free_tty_struct(struct tty_struct *tty)

释放未使用的 tty

参数

struct tty_struct *tty

要释放的 tty 结构

描述

释放写缓冲区、tty 队列和 tty 内存本身。

锁定:无。必须在 tty 确定未使用后调用

void tty_free_file(struct file *file)

释放 file->private_data

参数

struct file *file

释放 private_data

描述

这仅应用于未调用 tty_add_file 时的故障路径处理。

struct tty_driver *get_tty_driver(dev_t device, int *index)

查找 tty 的设备

参数

dev_t device

设备标识符

int *index

返回 tty 的索引

描述

此例程返回 tty 驱动程序结构,给定设备号,并返回索引号。

锁定:调用者必须持有 tty_mutex

struct file *tty_release_redirect(struct tty_struct *tty)

如果存在,则释放 pty 上的重定向

参数

struct tty_struct *tty

tty 设备

描述

pty 代码可以使用此函数,因此如果主设备关闭,则如果从设备是重定向,它可以释放重定向。

void __tty_hangup(struct tty_struct *tty, int exit_session)

挂起事件的实际处理程序

参数

struct tty_struct *tty

tty 设备

int exit_session

如果非零,则向所有前台组进程发送信号

描述

这可以由“kworker”内核线程调用。即进程同步,但不持有任何锁,因此我们需要确保我们为正在执行的操作持有适当的锁。

挂起事件会清除挂起设备上的任何挂起重定向。它确保将来的写入会出错,并且它会执行所需的行规程挂起和信号传递。tty 对象本身保持不变。

锁定
  • BTM

  • 用于撤消重定向的重定向锁

  • 用于操作 tty 列表的文件列表锁

  • 来自被调用函数的 tty_ldiscs_lock

  • 重置 termios 数据的 termios_rwsem

  • tasklist_lock 用于遍历任务列表以获取挂起事件

  • ->siglock 以保护 ->signal/->sighand

void tty_vhangup_self(void)

为自己的 ctty 执行进程 vhangup

参数

void

无参数

描述

对当前控制 tty 执行 vhangup

void tty_vhangup_session(struct tty_struct *tty)

挂起会话领导者退出

参数

struct tty_struct *tty

要挂起的 tty

描述

会话领导者正在退出并挂起其控制终端。前台进程组中的每个进程都会收到 SIGHUP 信号。

我们同步执行此操作,以便当系统调用返回时,进程完成。出于安全原因,这种保证是必要的。

ssize_t tty_read(struct kiocb *iocb, struct iov_iter *to)

tty 设备文件的读取方法

参数

struct kiocb *iocb

内核 I/O 控制块

struct iov_iter *to

读取数据的目标位置

描述

在此终端设备上执行读取系统调用功能。在调用行规程方法之前,检查挂起的设备。

锁定

在需要时内部锁定行规程。多个读取调用可以并行执行。

void tty_write_message(struct tty_struct *tty, char *msg)

将消息写入特定的 tty,而不仅仅是控制台。

参数

struct tty_struct *tty

目标 tty_struct

char *msg

要写入的消息

描述

这用于需要重定向到特定 tty 的消息。我们现在不把它放到 syslog 队列中,也许将来如果真的需要的话。

我们仍然必须持有 BTM 并测试此时的 CLOSING 标志。

此函数已弃用,请勿在新代码中使用。

ssize_t tty_write(struct kiocb *iocb, struct iov_iter *from)

tty 设备文件的写入方法

参数

struct kiocb *iocb

内核 I/O 控制块

struct iov_iter *from

包含要写入数据的 iov_iter

描述

通过行规程将数据写入 tty 设备。

锁定

根据需要锁定行规程。对 tty 驱动程序的写入由 atomic_write_lock 序列化,然后分块处理到设备。不会为每个设备并行调用行规程写入方法。

int tty_send_xchar(struct tty_struct *tty, u8 ch)

发送优先级字符

参数

struct tty_struct *tty

要发送到的 tty

u8 ch

要发送的 xchar

描述

即使停止,也要向 tty 发送高优先级字符。

锁定:xchar 方法无锁定,写入方法的写入排序。

void pty_line_name(struct tty_driver *driver, int index, char *p)

生成 pty 的名称

参数

struct tty_driver *driver

正在使用的 tty 驱动程序

int index

次要编号

char *p

至少 6 个字节的输出缓冲区

描述

driver 引用生成一个名称,并将其写入输出缓冲区 p

锁定:无

ssize_t tty_line_name(struct tty_driver *driver, int index, char *p)

生成 tty 的名称

参数

struct tty_driver *driver

正在使用的 tty 驱动程序

int index

次要编号

char *p

至少 7 个字节的输出缓冲区

描述

driver 引用生成一个名称,并将其写入输出缓冲区 p

锁定:无

struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, struct file *file, int idx)

查找现有的 tty(如果有)

参数

struct tty_driver *driver

tty 的驱动程序

struct file *file

文件对象

int idx

次要编号

返回

找到的 tty。如果未找到,则返回 NULL 或如果驱动程序 lookup() 方法返回错误,则返回 ERR_PTR()

描述

锁定:必须持有 tty_mutex。如果找到 tty,则增加 tty kref。

int tty_driver_install_tty(struct tty_driver *driver, struct tty_struct *tty)

在驱动程序中安装 tty 条目

参数

struct tty_driver *driver

tty 的驱动程序

struct tty_struct *tty

tty

描述

将 tty 对象安装到驱动程序表中。tty->index 字段将在调用此方法时设置。此方法负责确保分配和配置任何所需的其他结构。

锁定:目前是 tty_mutex

void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty)

从驱动程序表中移除一个 tty

参数

struct tty_driver *driver

tty 的驱动程序

struct tty_struct *tty

要移除的 tty

描述

从驱动程序表中移除一个 tty 对象。tty->index 字段会在调用此函数时设置。

锁定:目前是 tty_mutex

int tty_reopen(struct tty_struct *tty)

快速重新打开一个已打开的 tty

参数

struct tty_struct *tty

要打开的 tty

描述

不允许重新打开主 pty,并返回 -EIO

锁定:调用者必须持有 tty_lock

返回

成功返回 0,错误返回 -errno。

struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)

初始化一个 tty 设备

参数

struct tty_driver *driver

我们要在其上打开设备的 tty 驱动程序

int idx

设备索引

描述

准备一个 tty 设备。这可能不是一个“新的”干净的设备,也可能是一个活动的设备。由于这个原因,pty 驱动程序需要特殊处理。

锁定

该函数在 tty_mutex 下调用,这可以保护我们免受 tty 结构或驱动程序本身消失的影响。

退出时,tty 设备已附加了线路规程,并且引用计数为 1。如果为 pty/tty 用途创建了一个配对,并且另一个是 pty 主设备,则它的引用计数也为 1。

WSH 06/09/97:重写以消除竞争,并在打开失败后正确清理。新代码使用互斥锁保护打开操作,因此非常简单。对于重新打开 tty(最常见的情况),互斥锁的锁定可能可以放宽。

返回

新的 tty 结构

void tty_flush_works(struct tty_struct *tty)

刷新 tty/pty 配对的所有工作

参数

struct tty_struct *tty

要刷新工作的 tty 设备(或 pty 配对的任一端)

描述

同步刷新属于 tty(和“另一个”tty)的所有工作。

void release_one_tty(struct work_struct *work)

释放 tty 结构内存

参数

struct work_struct *work

我们要销毁的 tty 的工作

描述

释放与 tty 结构关联的内存,并清除驱动程序表槽。当设备不再使用时调用此函数。当设备设置失败时也会调用此函数。

锁定

在处理驱动程序维护的 tty 列表时,内部获取文件列表锁。

此方法从工作队列调用,以便驱动程序的私有清理操作可以休眠(至少对于 USB 需要)。

void release_tty(struct tty_struct *tty, int idx)

释放 tty 结构内存

参数

struct tty_struct *tty

tty 设备释放

int idx

要释放的 tty 设备的索引

描述

释放 tty 和可能的链接伙伴(考虑 pty 配对),并减少后备模块的引用计数。

锁定

tty_mutex 在处理驱动程序维护的 tty 列表时,内部获取文件列表锁。

int tty_release_checks(struct tty_struct *tty, int idx)

在真正释放之前检查一个 tty

参数

struct tty_struct *tty

要检查的 tty

int idx

tty 的索引

描述

在真正释放 tty 之前执行一些偏执的检查。除非定义了 TTY_PARANOIA_CHECK,否则这是一个空操作。

int tty_release(struct inode *inode, struct file *filp)

关闭的 vfs 回调

参数

struct inode *inode

tty 的 inode

struct file *filp

tty 句柄的文件指针

描述

每次关闭引用此 tty 的最后一个文件句柄时调用。但是,可能有多个此类引用。

锁定

获取 BKL。请参阅 tty_release_dev()。

即使释放 tty 结构也是一件棘手的事情。我们必须非常小心,确保所有结构同时释放,否则中断可能会获得错误的指针。

WSH 09/09/97:重写以避免一些可能导致双重释放或释放仍在使用的内存的糟糕竞争条件。

struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)

获取当前任务的锁定 tty

参数

dev_t device

设备编号

struct file *filp

指向 tty 的文件指针

返回

device 为 /dev/tty 时,当前任务的锁定 tty。

描述

执行当前任务的控制 tty 的重新打开操作。

我们不能像其他节点一样返回驱动程序和索引,因为 devpts 将无法工作。它希望 inode 来自 devpts FS。

struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, int *index)

查找给定设备文件的 tty 驱动程序

参数

dev_t device

设备编号

struct file *filp

指向 tty 的文件指针

int *index

返回 驱动程序中的设备索引

描述

如果返回值不是错误的,则调用者有责任通过 tty_driver_kref_put() 来减少引用计数。

加锁:tty_mutex 保护 get_tty_driver()

返回

此 inode 的驱动程序(引用计数增加)

struct tty_struct *tty_open_by_driver(dev_t device, struct file *filp)

打开 tty 设备

参数

dev_t device

要打开的设备的 dev_t

struct file *filp

指向 tty 的文件指针

描述

执行驱动程序查找,检查是否重新打开,否则执行首次 tty 初始化。

声明全局 tty_mutex 以序列化
  • 并发首次 tty 初始化

  • 并发 tty 驱动程序删除和查找

  • 从驱动程序表中并发删除 tty

返回

锁定初始化或重新打开的 tty_struct

int tty_open(struct inode *inode, struct file *filp)

打开 tty 设备

参数

struct inode *inode

设备文件的 inode

struct file *filp

指向 tty 的文件指针

描述

tty_open()tty_release() 维护 tty 计数,其中包含在 tty 上完成的打开次数。我们不能使用 inode 计数,因为不同的 inode 可能指向同一个 tty。

pty 主设备需要打开计数,以及用于跟踪串行线路:当最后一次关闭发生时,DTR 会被丢弃。(现在不仅仅是通过 tty->count 来完成的。- Ted 1/27/92)

pty 的 termios 状态在第一次打开时被重置,以便设置不会在重用时持续存在。

锁定

注意

由于 tty_mutex,没有引用的 tty_unlock/lock 情况是安全的

__poll_t tty_poll(struct file *filp, poll_table *wait)

检查 tty 状态

参数

struct file *filp

正在轮询的文件

poll_table *wait

要更新的轮询等待结构

描述

调用线路规程轮询方法以获取设备的轮询状态。

加锁:锁定调用的线路规程,但 ldisc 轮询方法可以被其他调用者自由地重新进入。

int tiocsti(struct tty_struct *tty, u8 __user *p)

伪造输入字符

参数

struct tty_struct *tty

要伪造输入到的 tty

u8 __user *p

指向字符的指针

描述

伪造到 tty 设备的输入。执行必要的加锁和输入管理。

FIXME:不遵守流量控制 ??

锁定
  • 被调用的函数采用 tty_ldiscs_lock

  • current->signal->tty 检查是安全的,无需锁定

int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)

实现窗口查询 ioctl

参数

struct tty_struct *tty

tty

struct winsize __user *arg

用户缓冲区的返回结果

描述

将内核窗口大小的概念复制到用户缓冲区中。

加锁:采用 tty->winsize_mutex 以确保 winsize 数据一致。

int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg)

实现窗口大小设置 ioctl

参数

struct tty_struct *tty

tty 端的 tty

struct winsize __user *arg

用户缓冲区的返回结果

描述

将用户窗口大小的概念复制到内核。传统上,这只是建议性信息,但对于 Linux 控制台,它实际上具有驱动程序级别的含义,并会触发 VC 大小调整。

锁定

驱动程序相关。默认的 do_resize 方法采用 tty termios 互斥锁和 ctrl.lock。控制台采用自己的锁,然后调用默认方法。

int tioccons(struct file *file)

允许管理员移动逻辑控制台

参数

struct file *file

成为控制台的文件

描述

允许管理员移动重定向的控制台设备。

加锁:使用 redirect_lock 来保护重定向信息

int tiocsetd(struct tty_struct *tty, int __user *p)

设置线路规程

参数

struct tty_struct *tty

tty 设备

int __user *p

指向用户数据的指针

描述

根据用户请求设置线路规程。

加锁:请参阅 tty_set_ldisc(),此函数只是一个辅助函数

int tiocgetd(struct tty_struct *tty, int __user *p)

获取线路规程

参数

struct tty_struct *tty

tty 设备

int __user *p

指向用户数据的指针

描述

直接从 ldisc 检索线路规程 ID。

加锁:等待 ldisc 引用(以防线路规程正在更改或 tty 正在挂起)

int send_break(struct tty_struct *tty, unsigned int duration)

执行时间中断

参数

struct tty_struct *tty

要中断的设备

unsigned int duration

超时时间,以毫秒为单位

描述

在缺乏自身驱动程序级别定时中断功能的硬件上执行定时中断。

锁定

tty->atomic_write_lock 序列化

int tty_tiocmget(struct tty_struct *tty, int __user *p)

获取调制解调器状态

参数

struct tty_struct *tty

tty 设备

int __user *p

指向结果的指针

描述

如果支持该功能,则从 tty 驱动程序获取调制解调器状态位。如果不可用,则返回 -ENOTTY

锁定:无(取决于驱动程序)

int tty_tiocmget(struct tty_struct *tty, unsigned int cmd, unsigned __user *p)

设置调制解调器状态

参数

struct tty_struct *tty

tty 设备

unsigned int cmd

命令 - 清除位、设置位或设置全部

unsigned __user *p

指向所需位的指针

描述

如果支持该功能,则从 tty 驱动程序设置调制解调器状态位。如果不可用,则返回 -ENOTTY

锁定:无(取决于驱动程序)

struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx)

分配一个新的 tty

参数

struct tty_driver *driver

将处理返回的 tty 的驱动程序

int idx

tty 的次设备号

描述

此子例程分配并初始化一个 tty 结构。

锁定:无 - 此处的 **tty** 此时未暴露