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
打开 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 结构
-
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 确定未使用后调用
参数
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
,否则这是一个空操作。
参数
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
参数
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,tty_lookup_driver()
和tty_init_dev()
。tty->count 应该保护其余部分。
->siglock 保护 ->signal/->sighand
注意
由于 tty_mutex
,没有引用的 tty_unlock/lock 情况是安全的
参数
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。控制台采用自己的锁,然后调用默认方法。
参数
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** 此时未暴露