我們打開一個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]