實現sleep-mysleep

sleep()—程序暫停若干時間。
模擬實現sleep—mysleep.
首先要了解三個函數:alarm,sigaction,pause
①alarm
這裏寫圖片描述
通俗來講,alarm是一個鬧鐘,鬧鐘是在你設定的時間後叫醒你,也就是告訴內核在seconds秒之後給當前進程發SIGALRM信號, 該信號的默認處理動作是終止當前進程。這個函數的返回值是0(意味着鬧鐘準時響了) ,因爲某些原因(你醒早了)鬧鐘提前響了,則返回的是剩下的秒數。
②sigaction(信號捕捉函數)
這裏寫圖片描述
sigaction函數可以讀取和修改與指定信號相關聯的處理動作。調用成功則返回0,出錯則返回- 1。
signo是指定信號的編號。若act指針非空,則根據act修改該信號的處理動作。若oact指針非 空,則通過oact傳出該信號原來的處理動作。act和oact指向sigaction結構體。
③pause
這裏寫圖片描述
庫函數使調用進程(或線程)睡眠狀態,直到接收到信號,要麼終止,或導致它調用一個信號捕獲函數。
返回值
只有當信號被抓獲和信號捕捉函數返回返回。 pause ()返回-1,並將 errno 設置爲 EINTR 。
代碼實現:

int mysleep(int timeout)  
{  
    struct sigaction act,oact;  
    act.sa_handler = myhandler;  
    sigemptyset(&act.sa_mask);  
    act.sa_flags = 0;  
    sigaction(SIGALRM,&act,&oact);  

    alarm(timeout);  
    pause();  
    int ret = alarm(0);  
    sigaction(SIGALRM,&oact,NULL);  
    return ret;  
}  

但是,有漏洞存在 : 註冊SIGALRM信號的處理函數,調用alarm(seconds)設定鬧鐘,內核調度優先級更高的進程取代當前進程執行,並且優先級更高的進程有很多個,每個都要執行很長時間seconds秒鐘之後鬧鐘超時了,內核發送SIGALRM信號給這個進程,處於未決狀態。優先級更高的進程執行完了,內核要調度回這個進程執行。SIGALRM信號遞達,執行處理函數sig_alrm之後再次進入內核。返回這個進程的主控制流程,alarm(seconds)返回,調用pause()掛起等待,可是SIGALRM信號已經處理完了,還在等待

int mysleep(int timeout)  
{  
    struct sigaction act,oact;  
    sigset_t newmask,oldmask,suspmask;  

    act.sa_handler = handler;  
    sigemptyset(&act.sa_mask);  
    act.sa_flags = 0;  
    sigaction(SIGALRM,&act,&oact);  

    sigemptyset(&newmask);  
    sigaddset(&newmask,SIGALRM);  
    sigprocmask(SIG_BLOCK,&newmask,&oldmask);  

    alarm(timeout);  

    suspmask = oldmask;  
    sigdelset(&suspmask,SIGALRM);  

    sigsuspend(&suspmask);  

    int ret = alarm(0);  
    sigaction(SIGALRM,&oact,NULL);  
    sigprocmask(SIG_SETMASK,&oldmask,NULL);  
    return ret;  
}  

如有錯誤,感謝指正

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章