linux中进程pts 1和pts 3,termial创建时ptmx与pts的关系

本文探讨了Linux系统中打开新终端时,/dev/pts下的pts节点如何由/dev/ptmx创建,并通过实例展示了多个进程同时读写同一pts设备时的数据竞争现象。当你在不同终端执行cat和ls命令时,会观察到数据交错显示,这是因为内核调度导致的数据争夺。分析了数据流程和异常现象背后的原因。

我们打开一个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]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值