一、利用pause和alarm函數實現sleep函數
#include <unistd.h>
int pause(void);
pause函數使調用進程掛起直到有訊號遞達。如果訊號的處理動作是終止進程,則進程終止,pause函數沒有機會返回;如果訊號的處理動作是忽略,則進程繼續處於掛起狀態,pause不返回;如果訊號的處理動作是捕捉,則調用了訊號處理函數之後pause返回-1,errno設定為EINTR,所以pause只有出錯的傳回值。錯誤碼EINTR表示“被訊號中斷”。
alarm函數可以參考這裡:http://blog.csdn.net/simba888888/article/details/8944647
下面使用pause和alarm實現sleep(3)函數,稱為mysleep:
#include<stdio.h>#include<signal.h>#include<unistd.h> void sig_alrm(int signo){ /* nothing to do */} unsigned int mysleep(unsigned int nsecs){ struct sigaction newact, oldact; unsigned int unslept; newact.sa_handler = sig_alrm; sigemptyset(&newact.sa_mask); newact.sa_flags = 0; sigaction(SIGALRM, &newact, &oldact); alarm(nsecs); pause(); unslept = alarm(0); sigaction(SIGALRM, &oldact, NULL); return unslept;} int main(void){ while (1) { mysleep(2); printf("Two seconds passed\n"); } return 0;}
1. main函數調用mysleep函數,後者調用sigaction註冊了SIGALRM訊號的處理函數sig_alrm。
2. 調用alarm(nsecs)設定鬧鐘。
3. 調用pause等待,核心切換到別的進程運行。
4. nsecs秒之後,鬧鐘逾時,核心發SIGALRM給這個進程。
5. 從核心態返回這個進程的使用者態之前處理未決訊號,發現有SIGALRM訊號,其處理函數是sig_alrm。
6. 切換到使用者態執行sig_alrm函數,進入sig_alrm函數時SIGALRM訊號被自動屏蔽,從sig_alrm函數返回時SIGALRM訊號自動解除屏蔽。然後自動執行系統調用sigreturn再次進入核心,再返回使用者態繼續執行進程的主控制流程程(main函數調用的mysleep函數)。