【转】浅析terminal创建时ptmx和pts关系
我们打开一个terminal,那么将会在devpts文件系统/dev/pts下创建一个对应的pts字符文件,
该pts字符文件节点直接由/dev/ptmx节点的驱动函数ptmx_open()
调用devpts_pty_new(tty->link)
[tty对应ptmx,tty->link对应/dev/pts/xxx,那么tty->link->link又对应回ptmx
同样ptm_driver->other等于pts_driver,pts_driver->other等于ptm_driver]主动创建,
而非通过netlink的udev或者hotplug配合创建[luther.gliethttp]
1.首先我们打开3个新的terminal终端
使用who am i查询当前终端对应的pts号
luther@gliethttp:~$ who am i
luther pts/3 2009-07-03 09:05 (:0.0)
luther@gliethttp:~$ who am i
luther pts/4 2009-07-03 09:08 (:0.0)
luther@gliethttp:~$ who am i
luther pts/5 2009-07-03 09:08 (:0.0)
他们分别对应pts 3,4和5.
2.在pts/4终端中执行如下命令
luther@gliethttp:~$ cat /dev/pts/3
llllllllls
3.在pts/3终端中输入平常的命令ls
你会发现输入的数据并不能被完全显示,而2步骤中运行的cat /dev/pts/3
命令确出现了不完整命令,这是怎么回事呢,接下来我们讲一讲该现象背后的故事[luther.gliethttp].
luther@gliethttp:~$ l
4.讲讲现象背后的故事
当ubuntu系统创建一个新的terminal时(比如上面的pts/3)
4.1 首先执行ptm = open('/dev/ptmx',...)操作
4.2 接下来fork(),然后child将打开'/dev/pts/3',dup2到0,1和2句柄上,随后执行execl启动一个shell.
pts = open('/dev/pts/3',...);
dup2(pts, 0); // 对应lib库中stdin
dup2(pts, 1); // 对应lib库中stdout
dup2(pts, 2); // 对应lib库中stderr
close(pts);
execl("/system/bin/sh", "/system/bin/sh", NULL);
// 这样sh输入数据将全部来自pts,
// sh的输出数据也都全部输送到pts,也就直接送到了打开ptmx的新terminal中.
4.3 新terminal将启动GUI,捕获按键数据,然后写入ptm,这样pts将收到数据,进而sh将从stdin中获得数据,
于是sh将作进一步运算,将结果送给stdout或stderr,进而送给pts,于是ptm获得数据,然后terminal的GUI
将数据显示出来.
具体流程图如下[luther.gliethttp]:
terminal捕获到key按键值 <--> ptm <--> pts/3 <--> stdin <--> shell读到数据
shell数据结果 <--> stdout <--> pts/3 <--> ptm <--> terminal显示
4.4 好了,正常的启动流程图已经有了,来看看,我们试验时数据出现显示异常的现象背后到底是怎么发生的.
与上面正常流程不同的时,我们在另外一个地方执行了cat.
这种情况下的流程图为[luther.gliethttp]:
terminal <--> ptm <--> pts/3 <------> shell
|
<------> 运行在pts/4上的 cat /dev/pts/3
很明显terminal发送数据到pts/3之后,
因为有2个独立的进程都在等待pts/3的数据,所以他们之间就发生了对pts/3数据抢夺现象,
因为linux内核调度器根据当时情况随时都会将他们中的一个调出或者调入,因此数据
就出现了一部分被送到了pts/4的cat命令,另一部分被送到了shell,
因为shell具有回显能力,shell将它接收到的所有字符串一一回显给terminal,所以terminal显示
到的数据就是shell与cat命令争抢数据时,shell自己抢到的数据,
而pts/4上显示的数据就是cat命令抢到的数据[luther.gliethttp]
比如我们仍然在pts/4上执行cat命令,然后我们在pts/5上执行echo命令
luther@gliethttp:~$ who am i
luther pts/5 2009-07-03 09:08 (:0.0)
luther@gliethttp:~$ echo 'luther.gliethttp' >/dev/pts/3
这时pts/3对应的terminal将完全显示'luther.gliethttp'字符串,因为没有人和ptm争抢数据[luther.gliethttp].
4.5 在pts/3自己所在terminal中执行cat回是什么现象呢,我么继续看看
luther@gliethttp:~$ cat /dev/pts/3
ls
ls
pwd
pwd
可以看到,输入ls回车之后,显示了2个ls,其中1个ls数据是cat命令自己回显出来的,
另外一个ls就来自/dev/pts/3文件,那这是怎么回事呢,原因是这样的,
cat和terminal都能获得键盘数据,cat将键盘数据直接回显到terminal上,
而terminal捕获的数据将通过ptm发送到pts/3,而cat自己又在等待pts/3的数据,所以
cat将从pts/3上再次读取到ptm发送过来的数据,再一次显示到terminal上,
那同样是cat pts/3,为什么就不一样呢,通过strace发现,如果在
terminal中直接调用库函数execve()执行另外一个shell命令,那么sh自身将停止对stdin进行数据读取,
只是等待shell命令退出,数据读取操作权完全交给被执行的shell命令(cat),
所以cat这时0,1,2都是对应pts/3,因为cat /dev/pts/3命令需要打开文件,
所以fd = open('/dev/pts/3',...)之后,fd数值将等于3,这样cat /dev/pts/3他的
0,1,2和3这4个句柄都对应pts/3节点[0为stdin,1为stdout,2为stderr]
所以读取pts/3的进程只有了一个,没有人和他争数据了,当然cat能够完全获得数据了,呵呵[luther.gliethttp]
【转】浅析terminal创建时ptmx和pts关系的更多相关文章
- (从终端看linux-2)浅析terminal创建时ptmx和pts关系
我们打开一个terminal,那么将会在devpts文件系统/dev/pts下创建一个对应的pts字符文件,该pts字符文件节点直接由/dev/ptmx节点的驱动函数ptmx_open()调用devp ...
- rebuild online 创建时,会话被Kill修复索引测试
rebuild online 创建时,会话被Kill修复索引 1.0实验目的:日常运维经常create index online,但是期间被kill会导致索引再次创建失败,测试解决该问题 2.0测试流 ...
- WM_SIZE后于WM_CREATE消息!!在窗口被创建时的顺序!
WM_SIZE procedure WMSize (var Message: TWMSize); message WM_SIZE; 参数说明 wParam: Specifies the type ...
- Java中对象创建时的内存分配
一.前言知识铺垫 1.逃逸对象:在一个方法内创建的对象没有被外界引用则称该对象为未逃逸的对象. 2.JDK1.6以后的HotSpot虚拟机支持运行时的对象逃逸分析. 3.JVM中的参数配置: 1) ...
- hibernate(四)__由表逆向创建Domain对象和对象关系映射文件
之前我们是手写Domain对象和对象关系映射文件->然后生成数据库中的Table. 现在我们反过来先在数据库中建好Table->然后用工具生成Domain对象和对象关系映射文件. 步骤: ...
- encfs创建时fuse: failed to exec fusermount: Permission denied错误解决
今天用encfs创建加密文件夹时碰到提示错误fuse: failed to exec fusermount: Permission denied fuse failed. Common problem ...
- 读书笔记-浅析Java运行时数据区
作为一个 Java 为主语言的程序员,我偶尔也需要 用 C/C++ 写程序,在使用时让我很烦恼的一件事情就是需要对 new 出来的对象进行 delete/free 操作,我老是担心忘了这件事情,从而导 ...
- iOS中单例创建时不严格造成的问题和解决方法
这次项目中遇到了一个单例创建不严格造成了的问题.简单说来就是在有的地方使用了alloc创建了多个实例,当然如果严格按照接口的方法调用是不会有问题的,但是如果项目碰到有不太熟悉的人使用时在处理时就会出现 ...
- SAP S/4HANA生产订单创建时使用的工厂数据是从什么地方带出来的
大家如果使用我github上的这段代码创建S/4HANA的生产订单时,一定会发现,我在代码里并没有硬编码来指定生产订单的ID,然而运行时会发现我在系统里配置的这个2800被自动使用了,这是怎么做到的呢 ...
随机推荐
- Android小记之--ClickableSpan
在给TextView设置超链接时,要想ClickableSpan的onClick事件响应,还必须同时设置tv.setMovementMethod(LinkMovementMethod.getInsta ...
- 类加载器子系统——JVM之四
一.类加载器基本概念 顾名思义,类加载器(class loader)用来加载 Java 类到 Java 虚拟机中.一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java ...
- Eclipse Plugin Dev Materials
以下资料是本人在开发Eclipse 插件时候收集的一些比较有用的资料Link,和大家分享下. 比较权威的资料: Helpful Eclipse Plugin Websites: Eclipse Art ...
- [python 基础] Class 一些基本概念
class example(object): data1 = '' date2 = "" def __init__(self, para): self._function1() d ...
- WINDOWS API 函数(超长,值得学习)
一.隐藏和显示光标 函数: int ShowCursor ( BOOL bShow ); 参数 bshow,为布尔型,bShow的值为False时隐藏光标,为True时显示光标:该函数的返回值为整型 ...
- spark快速入门之最简配置 spark 1.5.2 hadoop 2.7 配置
配置的伪分布式,ubuntu14.04上 先配置hadoop,参见这个博客,讲的很好 http://www.powerxing.com/install-hadoop/, 但是我在配的过程中还是遇到了问 ...
- poj 1083 Moving Tables_dp
题意:给你n个凳子,接着告诉你一个凳子从a房间到b房间,运输时间为10分钟,走廊很窄能通过一张凳子,当然不堵塞的话能同时扮凳子,问最小花费多少时间 因为数据很小就直接用数组统计了,a,b如果是奇数的话 ...
- Windows Server 2012 R2超级虚拟化之七 远程桌面服务的增强
Windows Server 2012 R2超级虚拟化之七 远程桌面服务的增强 在Windows Server 2012提供的远程桌面服务角色,使用户能够连接到虚拟桌面. RemoteApp程序.基 ...
- SNMP协议具体解释
简单网络管理协议(SNMP)是TCP/IP协议簇的一个应用层协议.在1988年被制定,并被Internet体系结构委员会(IAB)採纳作为一个短期的网络管理解决方式:因为SNMP的简单性,在Inter ...
- oracle子查询
子查询:在一个查询的内部包含另外一个查询. 普通子查询 -- 查询出比7654工资还高的所有雇员的信息 select * from emp e where e.sal > (select sal ...