20144303《資訊安全系統設計基礎》第十一周學習總結
代碼部分學習
forkdemo1:
運作結果:

第一次輸出Before,輸出的是父程序的pid。接下來調用fork,且将fork的傳回值(父程序的傳回值是子程序的pid,子程序的傳回值是0)指派給ret_form_fork。
然後輸出兩次After。第一個After是父程序的輸出,輸出父程序的pid為3927,輸出fork的傳回值(子程序的pid)為3928。 第二個After是子程序的輸出,輸出子程序的pid3928,fork的傳回值0
同時,多次運作這個程式發現每次輸出的pid都不相同,證明每次運作時系統賦予程序的pid都不同
forkdemo2:
輸出一次Before,輸出的是父程序的pid
輸出四次After,第一次輸出父程序的pid,後面三次輸出子程序的pid
同時,根據輸出的pid順序交叉,也可以看出這些程序是并發執行的
forkdemo3:
fork的傳回值:父程序傳回子程序的pid,子程序傳回0,錯誤傳回-1
Before輸出父程序的pid
将fork的傳回值指派給fork_rv,進行if判斷
執行父程序時,fork_rv不是0也不是-1,是以輸出i am parent,同時輸出子程序的pid
執行子程序時,fork_rv是0,輸出i am parent,同時輸出自己的pid
forkdemo4:
forkdemo4和forkdemo3大緻相同,隻要知道getppid函數的功能是獲得父程序的pid就能讀懂程式
forkgdb:
(把sleep的時間改大一些會便于觀察)
父子程序是并發執行的,當遇到sleep時,會結束目前程序,執行另一個程序。
是以,先輸出parent的li0、gi0,遇到sleep,轉到運作子程序,輸出child的li0,遇到sleep,轉到運作父程序,結束sleep後,輸出父程序的si0、li1、gi1,又遇到sleep。循環往複,直到全部輸出。
exec1:
函數說明:
execvp()會從PATH 環境變量所指的目錄中查找符合參數file 的檔案名,找到後便執行該檔案,然後将第二個參數argv傳給該欲執行的檔案。
傳回值:
如果執行成功則函數不會傳回,執行失敗則直接傳回-1,失敗原因存于errno中。
execvp()搜尋的PATH環境變量中指定的目錄中的ls指令的位置,而傳遞參數的ls指令在arglist中
第一個參數arglist[0]代表它要執行檔案的位置, 第二個參數arglist[1]是指令
将函數中的參數修改:
沒有輸出“* * * ls is done. bye”是因為execvp函數調用成功,沒有傳回
exec2:
exec1中,
execvp=(“ls”,arglist)
,execvp函數直接調用“ls”。
exec2中,
execvp=(arglist[0],arglist)
,execvp函數調用arglist[0],而arglist[0]中存放的是ls,是以輸出相同。
exec3:
execv、execlp、execvp、execvpe四個函數都能實作相同的功能。
函數execv():
int execv(const char *path, char *const argv[]);
execv會停止執行目前的程序,并且以被執行的應用程式替換被停止執行的程序,程序ID沒有改變。
argv: 傳遞給應用程式的參數清單, 注意,這個數組的第一個參數應該是應用程式名字本身,并且最後一個參數應該為NULL,不參将多個參數合并為一個參數放入數組。
函數execlp():
int execlp(const char *filename, const char arg0, ... / (char *)0 */ );
execlp()函數會從PATH環境變量所指的目錄中查找檔案名為第一個參數訓示的字元串,找到後執行該檔案,第二個及以後的參數代表執行檔案時傳遞的參數清單,最後一個參數必須是空指針.
函數execvp():
int execvp(const char *file, char *const argv[]);
execvp()函數會從PATH環境變量所指的目錄中查找檔案名為第一個參數訓示的字元串,找到後執行該檔案,第二個及以後的參數代表執行檔案時傳遞的參數清單,最後一個成員必須是空指針.
psh1:
與exec的功能大緻相同,psh1能實作參數的輸入,可以執行任意指令。
psh2:
在psh1的基礎上加了循環,可以多次輸入。
testbuf1:
在printf()後使用fflush(stdout)的作用是立刻将要輸出的内容輸出。
當使用printf()函數後,系統将内容存入輸出緩沖區,等到時間片輪轉到系統的輸出程式時,将其輸出。
使用fflush(out)後,立刻清空輸出緩沖區,并把緩沖區内容輸出。
while(1)是一個死循環,隻能強制退出
testbuf2:
testbuf3:
fprintf是用于檔案操作的
printf(...)等價于fprintf(stdout,...)
stdout:标準輸出裝置
stderr:标準錯誤輸出裝置
strerr是作為程式運作過程中的錯誤顯示出來的,預設情況下,标準輸入從鍵盤讀取,同時标準輸出和标準錯誤會列印到螢幕。
testpid:
輸出程序的pid和父程序的pid
testpp:
malloc 向系統申請配置設定指定size個位元組的記憶體空間。傳回類型是 void* 類型。
如果配置設定成功則傳回指向被配置設定記憶體的指針(此存儲區中的初始值不确定),否則傳回空指針NULL。當記憶體不再使用時,應使用free()函數将記憶體塊釋放。函數傳回的指針一定要适當對齊,使其可以用于任何資料對象。
提示出現段錯誤,可能是以下情況:
- 通路系統資料區,尤其是往 系統保護的記憶體位址寫資料 最常見就是給一個指針以0位址
- 記憶體越界(數組越界,變量類型不一緻等
- 通路到不屬于你的記憶體區域
testsystem:
waitdemo1:
wait(NULL)作用是等待子程序退出。NULL的意思是退出狀态不關注。
先輸出mypid,然後父程序,到wait語句時轉換到運作子程序,輸出“child pid here”,然後sleep,到exit(17)時,子程序退出,運作父程序,輸出“done waiting for 子程序pid”
waitdemo2:
在waitdemo1的基礎上,增加了輸出子程序的exit、sig、core
教材學習内容總結
8.1 異常
異常就是控制流中的突變,用來響應處理器狀态中的某些變化
8.1.1 異常處理
- 系統中可能的每種類型的異常都配置設定了一個唯一的非負整數的異常号。
- 處理器:被零除、缺頁、存儲器通路違例、斷點以及算術溢出
- 作業系統:系統調用和來自外部I/O裝置的信号
8.1.2異常的類别
- 中斷
- 來自I/O裝置的信号,異步,總是傳回到下一條指令
- 陷阱
- 有意的異常,同步,總是傳回到下一條指令
- 故障
- 潛在可恢複的錯誤,同步,可能傳回到目前指令
- 終止
- 不可恢複的錯誤,同步,不會傳回
8.1.3 Linux系統中的異常
Linux故障和終止
- 除法錯誤:異常号:0,通常報告為“浮點異常”
- 一般保護故障:異常号:13,Linux不會嘗試回複這類故障,通常報告為“段故障”
- 缺頁:異常号:14,是會重新執行産生故障的指令的一個異常事例
- 機器檢查:異常号:18,從不傳回控制給應用程式
Linux系統調用
每個系統調用都有一個唯一的整數号,對應于一個到核心中跳轉表的偏移量
将系統調用和與他們相關的包裝函數稱為系統級函數
8.2 程序
系統中的每個程式都是運作在某個程序的上下文中的。上下文是由程式正确運作所需的狀态組成的
8.2.1 邏輯控制流
- 程式計數器(PC)的值的序列叫做邏輯控制流,簡稱邏輯流
- 每個程序執行它的流的一部分,然後被搶占(暫時挂起),然後輪到其他程序
8.2.2 并發流
- 一個邏輯流的執行在時間上與另一個流重疊,稱為并發流
- 并發:多個流并發的執行的一般現象
- 多任務:一個程序和其他程序輪流運作
- 時間片:一個程序執行它的控制流的一部分的每一段時間
8.2.3 私有位址空間
這個空間中某個位址相關聯的那個存儲器位元組是不能被其他程序讀或者寫的
8.2.4 使用者模式和核心模式
- 當設定了模式位時,程序就運作在核心模式中
- 沒有設定模式位時,程序就運作在使用者模式中。使用者模式中的程序不允許執行特權指令。
- 程序從使用者模式變位核心模式的唯一方法是通過諸如中斷、故障或者陷入系統調用這樣的異常。
- /proc檔案系統允許使用者模式程序通路核心資料結構的内容
8.2.5 上下文切換
- 上下文切換:是較高形式的異常控制流來實作多任務
- 排程:在程序執行的某些時刻,核心可以決定搶占目前程序,并重新開始一個先前被搶占的程序。這種決定叫做排程
- 當核心代表使用者執行系統調用時,可能會發生上下文切換。如果系統調用因為等待某個事件發生阻塞,那麼核心可以讓目前程序休眠,切換到另一個程序
- 中斷也可能引發上下文切換
8.3 系統調用錯誤處理
- 定義錯誤報告函數,簡化代碼
- 錯誤處理包裝函數
8.4 程序控制
8.4.1擷取程序ID
- 每個程序都有一個唯一的正數程序ID
- gitpid函數傳回調用程序的PID,getppid函數傳回它的父程序的PID(建立調用程序的程序)
8.4.2 建立和終止程序
- 程序狀态:運作、停止、終止
- exit函數以status退出狀态來終止程序
- fork函數
- 父程序通過調用fork函數建立一個新的運作子程序
- 當父程序調用fork時,子程序可以讀寫父程序中打開的任何檔案
- 父程序和子程序之間最大的差別在于有不同的PID
- 調用一次,傳回兩次
- 并發執行
- 相同但是獨立的位址空間
- 共享檔案
8.4.3 回收子程序
- 僵死程序沒有運作,他們仍然消耗系統的存儲器資源
- 一個程序可以通過調用waitpid函數來等待它的子程序終止或停止
8.4.4 讓程序休眠
- sleep函數将一個程序挂起一段指定的時間
- pause函數讓調用函數休眠,直到該程序收到一個信号
8.4.5 加載并運作程式
- execve函數在目前程序的上下文中加載并運作一個新程式,execve調用一次并從不傳回
- argv參數清單,envp環境變量
- getenv函數
8.5 信号
- Unix信号:更高層的軟體形式的異常,允許程序中斷其他程序
- P505:30種不同類型的信号表
8.5.1 信号術語
- 發送信号:1)核心檢測到一個系統事件 2)一個程序調用了kill函數
- 接收信号:當目的程序被核心強迫以某種方式對發送的信号作出反應時,目的程序就接收了信号
- 待處理信号:一個隻發出而沒有被接收的信号
8.5.2 發送信号
程序組
每個程序都隻屬于一個程序組
一個程序可以通過使用setpigd函數來改變自己或者其他程序的程序組
用/bin/kill程式發送信号
一個為負的PID會導緻信号被發送到程序組PID中的每個程序中
8.5.3 接收信号
如果集合是非空的,那麼核心選擇集合中的某個信号k,并且強制p接收信号k
signal函數可以改變和信号signum相關聯的行為
8.5.4 信号處理問題
捕獲多個信号時的問題:
- 待處理信号被阻塞
- 待處理信号不會排隊等待
- 系統調用可以被中斷
8.5.5 可移植的信号處理
- 不同系統之間,信号處理語義有差異
- sigaction函數明确地指定它們想要的信号處理語義
8.5.6 顯式地阻塞和取消阻塞
- 應用程式可以使用sigprocmask函數顯式地阻塞和取消阻塞選擇的信号
- sigprocmask函數改變目前已阻塞信号的集合
8.6非本地跳轉
- 通過setjmp和longjmp函數來提供
- setjmp函數隻被調用一次,但傳回多次:一次是當第一次調用setjmp,而調用環境儲存在緩沖區env中時,一次是為每個相應的longjmp調用
- longjmp隻調用一次,但從不傳回
- 非本地跳轉的一個重要應用就是允許從一個深層嵌套的函數調用中立即傳回,通常是由檢測到某個錯誤情況引起的
- 非本地跳轉的另一個重要應用是使一個信号處理程式分支到一個特殊的代碼位置,而不是傳回到達中斷了的指令位置
8.7 操作程序的工具
Linux系統提供監控和操作程序的工具:列印一個正在運作的程式和它的子程序調用的每個系統調用的軌迹(STRACE)、列出目前系統中包括僵死程序的程序(PS)、列印出關于目前程序資源使用的資訊(TOP)、顯示程序的存儲器映射(PMAP)、虛拟檔案系統(/proc)
課後作業中的問題及解決
習題8.3:
剛開始看着道題的時候,認為有4種輸出序列:abcc、bacc、acbc、bcac。但是答案上隻寫了3個,沒有bcac。後來才發現,是忽略了waitpid函數。因為有waitpid,要等待子程序結束時,才會執行父程序的列印c指令。bcac是父程序都結束了,a程序還沒有開始,是以不會有這種輸出順序。
習題8.4:
這道題應該注意!pid是邏輯非運算,隻會輸出0或1。
另外就是注意父程序執行到waitpid函數時,要等子程序結束了才能繼續下一條指令
WIFEXITED,如果子程序通過調用exit或一個return正常終止,就傳回真值,是以當子程序正常結束的時候,會執行printf(“%d\n”,WEXITSTATUS(status))
WEXITSTATUS傳回一個正常終止的子程序的退出狀态。這段代碼中子程序的退出狀态是2,是以會輸出2
代碼托管
連結:https://git.oschina.net/20144303sys/work
感悟(其他)
本周的學習的主要内容是課本第八章以及老師在群裡發的代碼。在開始研究代碼之前,我先把課本第八章的知識認真學習了一遍。在對課本上内容有一定的掌握之後,開始看代碼,就感覺相對容易了一些。過程中遇到了一些不認識的函數和參數,也在網上也找到了答案。雖然這周學習量有點多,但收獲也不少。希望自己能保持學習的勢頭,再接再厲。
學習進度條
代碼行數(新增/累積) | 部落格量(新增/累積) | 學習時間(新增/累積) | 重要成長 |
---|---|---|---|
目标 | 5000行 | 30篇 | 400小時 |
第一周 | 0/0 | 1/1 | 20/20 |
第二周 | 300/300 | 1/2 | 20/40 |
第三周 | 300/600 | 1/3 | 20/60 |
第五周 | 200/800 | 2/5 | 20/80 |
第六周 | 100/900 | 2/7 | |
第七周 | 160/1060 | 1/8 | 20/100 |
第八周 | 0/1060 | 2/9 | 20/120 |
第九周 | 300/1360 | 2/11 | 20/140 |
第十周 | 495/1855 | 2/13 | 20/160 |
第十一周 | 1000/2855 | 2/15 | 20/180 |