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)相关推荐

  1. Linux中mknod命令实现原理以及源码分析

    本篇文章以mknod创建字符设备文件进行讲解 字符设备驱动的Demo例子可参考该篇文章 Linux 编写简单驱动并测试 1. mknod 命令 mknod /dev/hello c 520 0 该命令 ...

  2. linux的can通信busoff,socketCAN内核源码分析是否支持busoff自恢复--Apple的学习笔记

    大总结:诊断小系统搭建步骤总结--Apple的学习笔记的剩余问题2中,我说过要深入下socketCAN内核源码学习.因为这个小项目关于驱动开发太顺利了,导致学习不到什么东东.最主要我一开始走了捷径,看 ...

  3. Linux项目实战C++轻量级Web服务器源码分析TinyWebServer

    目录 文章简介 一. 先跑起来项目 二.再看项目核心 三.逐个击破!立下flag 文章简介 TinyWebServer是Linux下C++轻量级Web服务器,助力初学者快速实践网络编程,搭建属于自己的 ...

  4. 【分析笔记】Linux gpio_wdt.c 看门狗设备驱动源码分析

    基本原理 该看门狗的设备驱动实现原理很简单,比较主要的有两点: 一.定时器喂狗 通过定时器根据配置文件配置的喂狗方式(如脉冲切换.电平切换),对指定的 gpio 进行脉冲切换或电平切换实现喂狗. 脉冲 ...

  5. 字符设备-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  *   ...

  6. 关于Asp.net core配置信息读取的源码分析梳理

    概述 我们都知道asp.net core配置信息的读取离不开IConfigurationSource和IConfigurationProvider这两个类,ConfigurationSource可以提 ...

  7. Linux下存储多路径软件MultiPath源码分析

    2019独角兽企业重金招聘Python工程师标准>>> 全局概览 测试环境为CentOS 7 X64 从RPM获取源码 $ cd ~/rpmbuild/ $ yumdownloade ...

  8. 【Linux 内核 内存管理】mmap 系统调用源码分析 ④ ( do_mmap 函数执行流程 | do_mmap 函数源码 )

    文章目录 一.do_mmap 函数执行流程 二.do_mmap 函数源码 调用 mmap 系统调用 , 先检查 " 偏移 " 是否是 " 内存页大小 " 的 & ...

  9. Linux设备驱动简析—PC重启源码分析

    Linux在PC上的关机和重启可能由两种行为引发,一是通过用户编程,一是系统自己产生的消息.用户和系统进行交互的方式也有两个,一个是系统调用:sys_reboot,另一个就是apm或acpi的设备文件 ...

  10. Linux PPP实现源码分析-1

    前言: PPP(Point to Point Protocol)协议是一种广泛使用的数据链路层协议,在国内广泛使用的宽带拨号协议PPPoE其基础就是PPP协议,此外和PPP相关的协议PPTP,L2TP ...

最新文章

  1. 避免单线程单元 (STA) COM 组件
  2. Spark Streaming揭秘 Day9 从Receiver的设计到Spark框架的扩展
  3. 安卓9去掉搜索栏_安卓福音,史上最强搞机工具箱,一键修手机
  4. Hibernate4组件映射
  5. redhat 添加ssh端口_RHEL 7修改ssh默认端口号
  6. [汇编学习笔记][第十六章直接定址表]
  7. [WPF]WPF Data Virtualization和UI Virtualization
  8. 企业Linux系统部署OA系统上线实例
  9. python怎么重复程序,如何重复运行python程序
  10. gds文件 导出_RSoft CAD新的导入/导出GDS档案方法
  11. WSO2 ESB 5.0.0 的一些控制台显示配置
  12. 重新定义 \maketitle
  13. linux输入法中文输入法,RHEL7配置中文输入法-智能拼音
  14. 纺织ERP系统_纺织ERP软件_纺织面料系统
  15. SAP FICO-模块 关于固定资产年结和折旧的问题
  16. java作业Scanner收银
  17. [毕业设计]LaTeX论文模板排版
  18. C语言------函数
  19. 购物网站 前台后台 思维导图_【思维导图】前端开发JavaScript巩固你的JavaScript知识体系(网站同步更新)...
  20. Tableau 中的表计算图解(表和区的向下横穿)

热门文章

  1. 数据结构与算法实验01-使用链表实现多项式乘法
  2. ONGene:基于文献检索的肿瘤基因数据库
  3. 【docker-gpu】报错:W: GPG error:xxx, InRelease: The following signatures couldn‘t be verified because th
  4. 批处理文件(bat)装逼 之全彩滚动我爱你 绘制五彩爱心 绘制3D球体
  5. 关于word-break和word-wrap的使用和区别
  6. Windows10删除hiberfil.sys
  7. 2017年全国计算机软件水平考试报名入口网址V1.0(小虎整理)
  8. 2016年11月份各省市报考时间与报名链接 软考 系统集成项目管理工程师
  9. HDU-4622 Reincarnation (后缀自动机)
  10. 【读书分享】《解忧杂货店》东野圭吾