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

时间:2022-09-11 13:33:04

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

(从终端看linux-2)浅析terminal创建时ptmx和pts关系的更多相关文章

  1. 【转】浅析terminal创建时ptmx和pts关系

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

  2. &lpar;从终端看linux-1&rpar;linux tty pty pts 概念 区别

    基本概念: 1> tty(终端设备的统称):tty一词源于Teletypes,或者teletypewriters,原来指的是电传打字机,是通过串行线用打印机键盘通过阅读和发送信息的东西,后来这东 ...

  3. SQL Server on Linux 理由浅析

    SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...

  4. linux环境给mongodb创建索引

    首先我们来了解索引,如果有基础的可以直接看最后面的操作. 可参照 DoNotStop 的CSDN 博客 ,全文地址请点击: https://blog.csdn.net/u013725455/artic ...

  5. 看Linux 之父是如何定义 Linux?

    看Linux 之父是如何定义 Linux? LINUX是什么? LINUX是一个免费类unix内核,适用于386-AT计算机,附带完整源代码.主要让黑客.计算机科学学生使用,学习和享受.它大部分用C编 ...

  6. linux 6&period;5上创建新用户后&comma;不能登陆?

    linux 6.5上创建新用户后,不能登陆? 使用root账户登陆却可以! [root@ log]# useradd mtdk[root@ log]# echo 123abc |passwd --st ...

  7. linux网桥浅析

    linux网桥浅析 原文链接:http://hi.baidu.com/_kouu/item/25787d38efec56637c034bd0 什么是桥接?简单来说,桥接就是把一台机器上的若干个网络接口 ...

  8. linux 新进程的创建

    慕课18原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.背景知识: 1. ...

  9. 让Mac OS X下的终端像Linux那样拥有丰富多彩的颜色显示

    我们知道Linux下的命令行终端具有颜色回显功能,用ls命令查看目录或者文件,终端会以不同的颜色来区分:使用vim命令行编辑器打开脚本或其他源程序代码会以语法高亮模式显示.而Mac OS X下的终端却 ...

随机推荐

  1. 我们的动机(Our motivation)

    我们的动机(Our motivation) There are many PHP frameworks nowadays, but none of them is like Phalcon (Real ...

  2. POJ 1244 Slots of Fun&lpar;计算几何&rpar;

    题目链接 很简单的一题,数据 很小,直接暴力的.但是也是写也好久,有几个数,没算好...一次CE,一次PE,3Y. #include <iostream> #include <cst ...

  3. linux c

    #include <stdio.h>#include <string.h>#include <strings.h> int main(){    char buf[ ...

  4. &lpar;cljs&sol;run-at &lpar;JSVM&period; &colon;all&rpar; &quot&semi;一起实现柯里化&quot&semi;&rpar;

    前言  习惯了Ramda.js就会潜意识地认为函数均已柯里化,然后就可以随心所欲的用函数生成函数,或者使用compose组合多个函数来生成一个新函数.如下 const f = a => b =& ...

  5. Android Studio gradle插件版本和gradle版本对应关系

    1.gradle插件版本配置位置: project对应的build.gradle文件中 buildscript { repositories { jcenter() } dependencies { ...

  6. Android 播放内部mp3音乐

    private void heartSound() { try { AssetManager am = getAssets();//获得该应用的AssetManager AssetFileDescri ...

  7. js便签笔记(10) - 分享:json2&period;js源码解读笔记

    1. 如何理解“json” 首先应该意识到,json是一种数据转换格式,既然是个“格式”,就是个抽象的东西.它不是js对象,也不是字符串,它只是一种格式,一种规定而已. 这个格式规定了如何将js对象转 ...

  8. c4 L3-001 找零钱 (简单01背包-输出最小字典序解(用vector保存当前最优解))

    #include <iostream> #include <algorithm> #include <vector> #include <cstdio> ...

  9. Linux守护进程编写方法及原理

    什么守护进程? 守护进程是运行在后台的一种用来提供服务的进程,他脱离控制*立运行,守护进程是一种很有用的进 程. Linux的大多数服务器就是用守护进程实现的.比如,Internet服务器inetd ...

  10. CSS选取指定位置标签first-child、last-child、nth-child

    1.first-child 选择列表中的第一个标签. 2.last-child 选择列表中的最后一个标签 3.nth-child(n) 选择列表中的第n个标签 4.nth-child(2n) 选择列表 ...