天天看點

linux中程序pts 1和pts 3,termial建立時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号

[email protected]:~$ who am i

luther   pts/3        2009-07-03 09:05 (:0.0)

[email protected]:~$ who am i

luther   pts/4        2009-07-03 09:08 (:0.0)

[email protected]:~$ who am i

luther   pts/5        2009-07-03 09:08 (:0.0)

他們分别對應pts 3,4和5.

2.在pts/4終端中執行如下指令

[email protected]:~$ cat /dev/pts/3

llllllllls

3.在pts/3終端中輸入平常的指令ls

你會發現輸入的資料并不能被完全顯示,而2步驟中運作的cat  /dev/pts/3

指令确出現了不完整指令,這是怎麼回事呢,接下來我們講一講該現象背後的故事[luther.gliethttp].

[email protected]:~$ 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指令

[email protected]:~$ who am i

luther   pts/5        2009-07-03 09:08 (:0.0)

[email protected]:~$ echo 'luther.gliethttp' >/dev/pts/3

這時pts/3對應的terminal将完全顯示'luther.gliethttp'字元串,因為沒有人和ptm争搶資料[luther.gliethttp].

4.5 在pts/3自己所在terminal中執行cat回是什麼現象呢,我麼繼續看看

[email protected]:~$ 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]