实现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;  
}  

如有错误,感谢指正

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