BUAA_OS lab6實驗報告
一、思考題
1. 思考6.1
示例程式碼中,父程序操作管道的寫端,子程序操作管道的讀端。如果現在想讓父程序作為“讀者”,程式碼應當如何修改?
修改後程式碼如下(交換case 0 和default部分的程式碼):
2. 思考6.2
上面這種不同步修改 pp_ref 而導致的程序競爭問題在 user/fd.c 中的dup 函式中也存在。請結合程式碼模仿上述情景,分析一下我們的 dup 函式中為什麼會出現預想之外的情況?
考慮這樣的虛擬碼:
if(fork() == 0) {
dup(p[1]);
read(p[0]);
}
else {
dup(p[0]);
write(p[1]);
}
注意到在dup函式中,先對fd執行syscall_mem_map,後對data執行syscall_mem_map。
子程序先開始執行,執行到dup和read之間時發生時鐘中斷,此時pageref(p[1]) == 1,pageref(pipe) == 1;父程序開始執行,在dup函式中執行到fd的map之後,data的map之前,此時pageref(p[0]) == 1,pageref(pipe) == 1;時鐘中斷,子程序再次開始執行,此時執行read函式,判斷髮現pageref(p[0]) == pageref(pipe),誤認為是寫者全部結束,於是錯誤地返回了。
3. 思考6.3
閱讀上述材料並思考:為什麼系統呼叫一定是原子操作呢?如果你覺得不是所有的系統呼叫都是原子操作,請給出反例。希望能結合相關程式碼進行分析。
系統呼叫一定是原子操作,因為在通過系統呼叫陷入核心態時彙編程式碼關閉了時鐘中斷。
4. 思考6.4
仔細閱讀上面這段話,並思考下列問題
• 按照上述說法控制 pipeclose 中 fd 和 pipe unmap 的順序,是否可以解決上述場景的程序競爭問題?給出你的分析過程。
• 我們只分析了 close 時的情形,在 fd.c 中有一個 dup 函式,用於複製檔案內容。試想,如果要複製的是一個管道,那麼是否會出現與 close 類似的問題?請模仿上述材料寫寫你的理解。
-
可以解決。最初pageref(p[0]) = 2,pageref(p[1]) = 2,pageref(pipe) = 4;仍考慮子程序先執行,對p[1]執行close函式時先解除了對寫端fd的對映,之後發生時鐘中斷,此時pageref(p[0]) = 2,pageref(p[1]) = 1,pageref(pipe) = 4;父程序執行完close(p[0])後,pageref(p[0]) = 1,pageref(p[1]) = 1,pageref(pipe) = 3,父程序開始執行時仍不滿足寫端關閉的條件,因此競爭問題沒有出現。
-
在程式執行時,總滿足pageref(p[0]) ≤ pageref(pipe),如果在dep中先對fd進行對映,此時fd的rep先增加,可能填補了二者的空隙,造成讀端已滿的假象(寫端同理),因此也會出現與close相似的問題,需要調整對映的順序。
5. 思考6.5
bss 在 ELF 中並不佔空間,但 ELF 載入進記憶體後,bss 段的資料佔據了空間,並且初始值都是 0。請回答你設計的函式是如何實現上面這點的?
與lab3實現幾乎完全相同,當系統呼叫執行sys_mem_alloc函式時進一步呼叫了page_alloc函式,其中有bzero使新分配的頁面內容全部為0,只要不向資料段錯誤地複製內容,即可保證該段初始值為0。
6. 思考6.6
為什麼我們的 *.b 的 text 段偏移值都是一樣的,為固定值?
觀察user/user.lds檔案內容,有如下程式碼:
. = 0x00400000;
_text = .; /* Text and read-only data */
.text : {
*(.text)
*(.fixup)
*(.gnu.warning)
}
這說明所有檔案在連結時都以此規定相同的起始地址。
7.思考6.7
在哪步,0和1被“安排”為標準輸入和標準輸出?請分析程式碼執行流程,給出答案。
在user/init.c中,有如下程式碼,在此處將0和1安排為了標準輸入輸出:
close(0);
if ((r = opencons()) < 0)
user_panic("opencons: %e", r);
if (r != 0)
user_panic("first opencons used fd %d", r);
if ((r = dup(0, 1)) < 0)
user_panic("dup: %d", r);
二、實驗難點
1. 管道與程序切換
由於時鐘中斷可能在函式執行中間發生,而有時需要保證同步性,因此需要注意判斷是否在同一時間片內。_pipeisclosed函式中就需要運用env_runs變數計數程序執行次數,只有在同一次數內才能保證pageref的同步性。
2. spawn
三、體會與感想
本次lab用時13小時,相比於前幾個lab用時少了很多,也可能是因為到了考期,而且沒有了課上測試的要求,有些程式碼沒有很認真地理解,做得有些潦草。計劃考期結束後重新過一遍,加深對管道的理解。
實現完檔案系統和管道後,作業系統似乎更加有意思了起來,原來只是對著一塊黑黑的螢幕寫一些十分抽象的程式碼,執行結果也只是一些printf的輸出,而現在可以自己建立檔案,可以實現控制檯中斷,與控制檯互動等,隨便敲敲都會有顯示,於是像個沒見過世面的小孩子,覺得驚喜又有趣。
四、殘留難點
對填寫範圍以外的官方程式碼理解還不透徹,需要鞥更細緻的學習。