我们打开一个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关系的更多相关文章

  1. (从终端看linux-2)浅析terminal创建时ptmx和pts关系

    我们打开一个terminal,那么将会在devpts文件系统/dev/pts下创建一个对应的pts字符文件,该pts字符文件节点直接由/dev/ptmx节点的驱动函数ptmx_open()调用devp ...

  2. rebuild online 创建时,会话被Kill修复索引测试

    rebuild online 创建时,会话被Kill修复索引 1.0实验目的:日常运维经常create index online,但是期间被kill会导致索引再次创建失败,测试解决该问题 2.0测试流 ...

  3. WM_SIZE后于WM_CREATE消息!!在窗口被创建时的顺序!

    WM_SIZE   procedure WMSize (var Message: TWMSize); message WM_SIZE; 参数说明 wParam: Specifies the type ...

  4. Java中对象创建时的内存分配

    一.前言知识铺垫   1.逃逸对象:在一个方法内创建的对象没有被外界引用则称该对象为未逃逸的对象. 2.JDK1.6以后的HotSpot虚拟机支持运行时的对象逃逸分析. 3.JVM中的参数配置: 1) ...

  5. hibernate(四)__由表逆向创建Domain对象和对象关系映射文件

    之前我们是手写Domain对象和对象关系映射文件->然后生成数据库中的Table. 现在我们反过来先在数据库中建好Table->然后用工具生成Domain对象和对象关系映射文件. 步骤: ...

  6. encfs创建时fuse: failed to exec fusermount: Permission denied错误解决

    今天用encfs创建加密文件夹时碰到提示错误fuse: failed to exec fusermount: Permission denied fuse failed. Common problem ...

  7. 读书笔记-浅析Java运行时数据区

    作为一个 Java 为主语言的程序员,我偶尔也需要 用 C/C++ 写程序,在使用时让我很烦恼的一件事情就是需要对 new 出来的对象进行 delete/free 操作,我老是担心忘了这件事情,从而导 ...

  8. iOS中单例创建时不严格造成的问题和解决方法

    这次项目中遇到了一个单例创建不严格造成了的问题.简单说来就是在有的地方使用了alloc创建了多个实例,当然如果严格按照接口的方法调用是不会有问题的,但是如果项目碰到有不太熟悉的人使用时在处理时就会出现 ...

  9. SAP S/4HANA生产订单创建时使用的工厂数据是从什么地方带出来的

    大家如果使用我github上的这段代码创建S/4HANA的生产订单时,一定会发现,我在代码里并没有硬编码来指定生产订单的ID,然而运行时会发现我在系统里配置的这个2800被自动使用了,这是怎么做到的呢 ...

随机推荐

  1. 握手(bestcode#42)

    Shaking hands 问题描述 今天是Gorwin的生日,所以她举办了一个派对并邀请她的朋友来参加.她将邀请n个朋友,为了方便,Gorwin把他们从1到n标号.他们之中有一些人已经相互认识,有一 ...

  2. static_cast与dynamic_cast转换 最简单的理解

    3.1 static_cast用法:static_cast < type-id > ( exdivssion ) 该运算符把exdivssion转换为type-id类型,但没有运行时类型检 ...

  3. vs2005的MFC程序在64位机上不能运行

    出现上述错误大多因为该机上没有安装vs2005程序,vs2005要运行需要一些必要的文件,没有添加到你发布的可执行文件目录下,所以程序不能运行. 解决方法: 安装目录\Microsoft Visual ...

  4. codility上的练习(3)

    今天发现又出了lesson 3... 不过题目都很简单…… (1) Min-avg-slice 给定一个长度为n的整数数组,找到一个连续的子数组,数组元素的平均值最小. 数据范围N [1..10^5] ...

  5. Codeforces #344 Div.2

    Codeforces #344 Div.2 Interview 题目描述:求两个序列的子序列或操作的和的最大值 solution 签到题 时间复杂度:\(O(n^2)\) Print Check 题目 ...

  6. ubuntu 命令

    用mount命令加载iso到虚拟光驱 先在/media/目录下新建一个空目录作为加载iso的虚拟光驱名称: sudo mkdir /media/aaaa 再用mount挂载: sudo mount - ...

  7. 高龄“潮男”优衣库老板柳井正_榜样_奢华主义_YOKA时尚网

    高龄"潮男"优衣库老板柳井正_榜样_奢华主义_YOKA时尚网 高龄"潮男"优衣库老板柳井正

  8. 委托-异步调用-泛型委托-匿名方法-Lambda表达式-事件【转】

    1. 委托 From: http://www.cnblogs.com/daxnet/archive/2008/11/08/1687014.html 类是对象的抽象,而委托则可以看成是函数的抽象.一个委 ...

  9. c#中 HttpContext作用(一)【转】

    HttpContext 主要作用是要获得你客户端向服务端请求提交的相关信息  HttpContext 类:封装有关个别 HTTP 请求的所有 HTTP  特定的信息.也有人叫上下文信息. 1.生存周期 ...

  10. Data Recovery Advisor (DRA)

    数据恢复指导Data Recovery Advisor (DRA)的适用场景:Data Recovery Advisor 是11g 新特性,是Oracle 顾问程序架构的一部分,它会在遇到错误时自动收 ...