linux tty core code,linux tty core 源码分析(8)
tty_ioctl和tty_compat_ioctl都是对设备的控制操作,比较容易理解这里就不做分析,有兴趣的读者可以自己分析。其中tty_compat_ioctl使用在用户空间为32位模式而内核空间为64位模式时将64位转化为32位的操作方式。
剩下的就是最后的操作,当关闭tty设备是调用的tty_release操作,主要是释放前面分配的资费做tty_open的反操作
/**
* tty_release - vfs callback for close
* @inode: inode of tty
* @filp: file pointer for handle to tty
*
* Called the last time each file handle is closed that references
* this tty. There may however be several such references.
*
* Locking:
* Takes bkl. See release_dev
*/
static int tty_release(struct inode *inode, struct file *filp)
{
lock_kernel();
release_dev(filp);
unlock_kernel();
return 0;
}
/*
* Even releasing the tty structures is a tricky business.. We have
* to be very careful that the structures are all released at the
* same time, as interrupts might otherwise get the wrong pointers.
*
* WSH 09/09/97: rewritten to avoid some nasty race conditions that could
* lead to double frees or releasing memory still in use.
*/
static void release_dev(struct file *filp)
{
struct tty_struct *tty, *o_tty;
int pty_master, tty_closing, o_tty_closing, do_sleep;
int devpts;
int idx;
char buf[64];
tty = (struct tty_struct *)filp->private_data;
if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode,
"release_dev"))
return;
check_tty_count(tty, "release_dev"); //对tty设备打开次数进行统计,tty设备的每次打开tty->files创建一个文件描述符
tty_fasync(-1, filp, 0); //从文件队列中删去异步通知结构struct fasync_struct
idx = tty->index;
pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER); //设备是伪终端主设备 devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
o_tty = tty->link;
//对设备在驱动对应对对象进行检查
#ifdef TTY_PARANOIA_CHECK
if (idx < 0 || idx >= tty->driver->num) {
printk(KERN_DEBUG "release_dev: bad idx when trying to "
"free (%s)/n", tty->name);
return;
}
if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
if (tty != tty->driver->ttys[idx]) {
printk(KERN_DEBUG "release_dev: driver.table[%d] not tty "
"for (%s)/n", idx, tty->name);
return;
}
if (tty->termios != tty->driver->termios[idx]) {
printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios "
"for (%s)/n",
idx, tty->name);
return;
}
if (tty->termios_locked != tty->driver->termios_locked[idx]) {
printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not "
"termios_locked for (%s)/n",
idx, tty->name);
return;
}
}
#endif
#ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "release_dev of %s (tty count=%d)...",
tty_name(tty, buf), tty->count);
#endif
//伪终端设备对等端的检查
#ifdef TTY_PARANOIA_CHECK
if (tty->driver->other &&
!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
if (o_tty != tty->driver->other->ttys[idx]) {
printk(KERN_DEBUG "release_dev: other->table[%d] "
"not o_tty for (%s)/n",
idx, tty->name);
return;
}
if (o_tty->termios != tty->driver->other->termios[idx]) {
printk(KERN_DEBUG "release_dev: other->termios[%d] "
"not o_termios for (%s)/n",
idx, tty->name);
return;
}
if (o_tty->termios_locked !=
tty->driver->other->termios_locked[idx]) {
printk(KERN_DEBUG "release_dev: other->termios_locked["
"%d] not o_termios_locked for (%s)/n",
idx, tty->name);
return;
}
if (o_tty->link != tty) {
printk(KERN_DEBUG "release_dev: bad pty pointers/n");
return;
}
}
#endif
if (tty->ops->close)
tty->ops->close(tty, filp); //调用tty->ops->close释放相应资源
/*
* Sanity check: if tty->count is going to zero, there shouldn't be
* any waiters on tty->read_wait or tty->write_wait. We test the
* wait queues and kick everyone out _before_ actually starting to
* close. This ensures that we won't block while releasing the tty
* structure.
*
* The test for the o_tty closing is necessary, since the master and
* slave sides may close in any order. If the slave side closes out
* first, its count will be one, since the master side holds an open.
* Thus this test wouldn't be triggered at the time the slave closes,
* so we do it now.
*
* Note that it's possible for the tty to be opened again while we're
* flushing out waiters. By recalculating the closing flags before
* each iteration we avoid any problems.
*/
while (1) { //循环操作,知道tty设备的的读写操作都完成才退出循环 /* Guard against races with tty->count changes elsewhere and
opens on /dev/tty */
mutex_lock(&tty_mutex);
tty_closing = tty->count <= 1; //是否执行真正的关闭 o_tty_closing = o_tty &&
(o_tty->count <= (pty_master ? 1 : 0));
do_sleep = 0;
if (tty_closing) { //在设备关闭前先完成等待的读写操作 if (waitqueue_active(&tty->read_wait)) {
wake_up(&tty->read_wait);
do_sleep++;
}
if (waitqueue_active(&tty->write_wait)) {
wake_up(&tty->write_wait);
do_sleep++;
}
}
if (o_tty_closing) {
if (waitqueue_active(&o_tty->read_wait)) {
wake_up(&o_tty->read_wait);
do_sleep++;
}
if (waitqueue_active(&o_tty->write_wait)) {
wake_up(&o_tty->write_wait);
do_sleep++;
}
}
if (!do_sleep) //完成所有的读写操作 break;
printk(KERN_WARNING "release_dev: %s: read/write wait queue "
"active!/n", tty_name(tty, buf));
mutex_unlock(&tty_mutex);
schedule();
}
/*
* The closing flags are now consistent with the open counts on
* both sides, and we've completed the last operation that could
* block, so it's safe to proceed with closing.
*/
if (pty_master) {
if (--o_tty->count < 0) {
printk(KERN_WARNING "release_dev: bad pty slave count "
"(%d) for %s/n",
o_tty->count, tty_name(o_tty, buf));
o_tty->count = 0;
}
}
if (--tty->count < 0) {
printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s/n",
tty->count, tty_name(tty, buf));
tty->count = 0;
}
/*
* We've decremented tty->count, so we need to remove this file
* descriptor off the tty->tty_files list; this serves two
* purposes:
* - check_tty_count sees the correct number of file descriptors
* associated with this tty.
* - do_tty_hangup no longer sees this file descriptor as
* something that needs to be handled for hangups.
*/
file_kill(filp); //关闭文件描述符 filp->private_data = NULL;
/*
* Perform some housekeeping before deciding whether to return.
*
* Set the TTY_CLOSING flag if this was the last open. In the
* case of a pty we may have to wait around for the other side
* to close, and TTY_CLOSING makes sure we can't be reopened.
*/
if (tty_closing)
set_bit(TTY_CLOSING, &tty->flags);
if (o_tty_closing)
set_bit(TTY_CLOSING, &o_tty->flags);
/*
* If _either_ side is closing, make sure there aren't any
* processes that still think tty or o_tty is their controlling
* tty.
*/
if (tty_closing || o_tty_closing) {
read_lock(&tasklist_lock);
session_clear_tty(tty->session);
if (o_tty)
session_clear_tty(o_tty->session);
read_unlock(&tasklist_lock);
}
mutex_unlock(&tty_mutex);
/* check whether both sides are closing ... */
if (!tty_closing || (o_tty && !o_tty_closing))
return;
#ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "freeing tty structure...");
#endif
/*
* Ask the line discipline code to release its structures
*/
tty_ldisc_release(tty, o_tty);
/*
* The release_tty function takes care of the details of clearing
* the slots and preserving the termios structure.
*/
release_tty(tty, idx);
/* Make this pty number available for reallocation */
if (devpts)
devpts_kill_index(idx);
}
自此我们分析了linux操作系统中/dev/tty /dev/tty0 /dev/console等设备作为字符设备的驱动程序,同时tty核心也为其他tty设备驱动的注册提供了一个通用的接口和一个通用的管理平台,为其他tty设备驱动的实现提供了一个通用层,下一节中我们将分析tty设备驱动的管理以及如何利用tty核心去实现一个tty设备驱动。
linux tty core code,linux tty core 源码分析(8)相关推荐
- Linux中mknod命令实现原理以及源码分析
本篇文章以mknod创建字符设备文件进行讲解 字符设备驱动的Demo例子可参考该篇文章 Linux 编写简单驱动并测试 1. mknod 命令 mknod /dev/hello c 520 0 该命令 ...
- linux的can通信busoff,socketCAN内核源码分析是否支持busoff自恢复--Apple的学习笔记
大总结:诊断小系统搭建步骤总结--Apple的学习笔记的剩余问题2中,我说过要深入下socketCAN内核源码学习.因为这个小项目关于驱动开发太顺利了,导致学习不到什么东东.最主要我一开始走了捷径,看 ...
- Linux项目实战C++轻量级Web服务器源码分析TinyWebServer
目录 文章简介 一. 先跑起来项目 二.再看项目核心 三.逐个击破!立下flag 文章简介 TinyWebServer是Linux下C++轻量级Web服务器,助力初学者快速实践网络编程,搭建属于自己的 ...
- 【分析笔记】Linux gpio_wdt.c 看门狗设备驱动源码分析
基本原理 该看门狗的设备驱动实现原理很简单,比较主要的有两点: 一.定时器喂狗 通过定时器根据配置文件配置的喂狗方式(如脉冲切换.电平切换),对指定的 gpio 进行脉冲切换或电平切换实现喂狗. 脉冲 ...
- 字符设备-seria.c tty_io.c seria.c rs_io.s tty_iocnl.c tty.h termios.h keyboard.s源码分析
这篇文章,很多语句我并没有给出注释,因为大都是宏定义.表格定义等语句,贴出来更多的是为了这一系列的完整性. 1 /* 2 * linux/kernel/serial.c 3 * ...
- 关于Asp.net core配置信息读取的源码分析梳理
概述 我们都知道asp.net core配置信息的读取离不开IConfigurationSource和IConfigurationProvider这两个类,ConfigurationSource可以提 ...
- Linux下存储多路径软件MultiPath源码分析
2019独角兽企业重金招聘Python工程师标准>>> 全局概览 测试环境为CentOS 7 X64 从RPM获取源码 $ cd ~/rpmbuild/ $ yumdownloade ...
- 【Linux 内核 内存管理】mmap 系统调用源码分析 ④ ( do_mmap 函数执行流程 | do_mmap 函数源码 )
文章目录 一.do_mmap 函数执行流程 二.do_mmap 函数源码 调用 mmap 系统调用 , 先检查 " 偏移 " 是否是 " 内存页大小 " 的 & ...
- Linux设备驱动简析—PC重启源码分析
Linux在PC上的关机和重启可能由两种行为引发,一是通过用户编程,一是系统自己产生的消息.用户和系统进行交互的方式也有两个,一个是系统调用:sys_reboot,另一个就是apm或acpi的设备文件 ...
- Linux PPP实现源码分析-1
前言: PPP(Point to Point Protocol)协议是一种广泛使用的数据链路层协议,在国内广泛使用的宽带拨号协议PPPoE其基础就是PPP协议,此外和PPP相关的协议PPTP,L2TP ...
最新文章
- 避免单线程单元 (STA) COM 组件
- Spark Streaming揭秘 Day9 从Receiver的设计到Spark框架的扩展
- 安卓9去掉搜索栏_安卓福音,史上最强搞机工具箱,一键修手机
- Hibernate4组件映射
- redhat 添加ssh端口_RHEL 7修改ssh默认端口号
- [汇编学习笔记][第十六章直接定址表]
- [WPF]WPF Data Virtualization和UI Virtualization
- 企业Linux系统部署OA系统上线实例
- python怎么重复程序,如何重复运行python程序
- gds文件 导出_RSoft CAD新的导入/导出GDS档案方法
- WSO2 ESB 5.0.0 的一些控制台显示配置
- 重新定义 \maketitle
- linux输入法中文输入法,RHEL7配置中文输入法-智能拼音
- 纺织ERP系统_纺织ERP软件_纺织面料系统
- SAP FICO-模块 关于固定资产年结和折旧的问题
- java作业Scanner收银
- [毕业设计]LaTeX论文模板排版
- C语言------函数
- 购物网站 前台后台 思维导图_【思维导图】前端开发JavaScript巩固你的JavaScript知识体系(网站同步更新)...
- Tableau 中的表计算图解(表和区的向下横穿)
热门文章
- 数据结构与算法实验01-使用链表实现多项式乘法
- ONGene:基于文献检索的肿瘤基因数据库
- 【docker-gpu】报错:W: GPG error:xxx, InRelease: The following signatures couldn‘t be verified because th
- 批处理文件(bat)装逼 之全彩滚动我爱你 绘制五彩爱心 绘制3D球体
- 关于word-break和word-wrap的使用和区别
- Windows10删除hiberfil.sys
- 2017年全国计算机软件水平考试报名入口网址V1.0(小虎整理)
- 2016年11月份各省市报考时间与报名链接 软考 系统集成项目管理工程师
- HDU-4622 Reincarnation (后缀自动机)
- 【读书分享】《解忧杂货店》东野圭吾