CSAPP LAB之shlab,進(jìn)程、信號、shell

shlab實(shí)現(xiàn)一個(gè)tiny shell,有fg、bg、jobs、quit四個(gè)內(nèi)置命令,可以調(diào)用其他命令,可以在命令后加&指明在后臺執(zhí)行,可以通過ctrl+c中斷前臺進(jìn)程,可以用ctrl+z暫停前臺進(jìn)程。這個(gè)lab主要是熟悉進(jìn)程和信號,看似只有兩個(gè)概念,但是這兩個(gè)概念的細(xì)節(jié)非常多和雜,需要對它們有比較全面和深入的理解。
官方已經(jīng)給出了整體框架,我們需要完成下面的函數(shù):
eval、builtin_cmd、do_bgfg、waitfg、sigchld_handler、sigint_handler、sigtstp_handler?
具體的實(shí)現(xiàn)可以參看這篇文章,寫的比較詳細(xì)https://zhuanlan.zhihu.com/p/422490811。
下面說說一些需要注意的點(diǎn)
1、 前臺可能是一個(gè)進(jìn)程,也可能是一個(gè)進(jìn)程組,包含多個(gè)進(jìn)程;
比如當(dāng)我們的tsh運(yùn)行時(shí),就位于系統(tǒng)shell的前臺,當(dāng)它運(yùn)行一個(gè)程序,fork子進(jìn)程后,默認(rèn)它們是同一個(gè)組,子進(jìn)程還可能再fork孫進(jìn)程,子子孫孫無窮盡,但是默認(rèn)他們都和tsh位于同一個(gè)進(jìn)程組。這里要區(qū)別系統(tǒng)shell的前后臺和tsh的前后臺,tsh運(yùn)行后對于系統(tǒng)shell是前臺,tsh的前臺是它等待結(jié)束的命令。
tsh有兩個(gè)地方跟上述相關(guān),
第一,?? ctrl+c和ctrl+z會同時(shí)發(fā)送給父進(jìn)程(tsh)和n個(gè)子進(jìn)程(它們構(gòu)成系統(tǒng)shell的前臺進(jìn)程組),tsh收到信號會捕獲然后處理,所有子進(jìn)程收到會按照默認(rèn)方式處理。而我們的要求是中斷或者暫停tsh的前臺,所以要把tsh的子進(jìn)程獨(dú)立成組,讓tsh自己成組,鍵盤信號只發(fā)送給tsh,然后它捕獲后再發(fā)送給它的前臺子進(jìn)程組。
第二,?? kill的第一個(gè)參數(shù)是-pid,負(fù)的pid表示發(fā)送信號到進(jìn)程組為pid的所有進(jìn)程,如果是pid,則只發(fā)給對應(yīng)的進(jìn)程,該進(jìn)程的子進(jìn)程就會成為僵尸進(jìn)程。

2、訪問全局共享變量要同步,防止因?yàn)椴l(fā)導(dǎo)致的問題。具體辦法就是訪問前阻塞信號,訪問后解除阻塞。
下面是我的代碼,供大家參考
我搞了個(gè)簡單的shell腳本,可以一下測試所有的test。
測試自己的tsh,輸出保存到?tshtest.txt中。
./test.sh test >?tshtest.txt
測試參考tshref,輸出保存到?tshreftest.txt中。
./test.sh rtest >?tshreftest.txt
最好不要同時(shí)運(yùn)行上面的命令,因?yàn)橛行﹖est會運(yùn)行ps a命令,同時(shí)會讓輸出變得混亂。
然后可以使用文件比較工具輸出

github地址:https://github.com/gyxkgz/csapp-lab-solution