一、实验目的
学习和掌握sleep函数中alarm的调用。
二、实验要求
函数名字和原型:
unsigned int mysleep(unsignedint);
该函数的功能要求与UNIX的sleep函数一样。
1、使用alarm函数实现定时。
2、必须正确处理mysleep函数中的闹钟与调用者可能设置的闹钟之间的关系。例如,如何解决不同的信号处理函数的保存和恢复?如何处理调用者设置的闹钟比mysleep函数中的闹钟早响的问题?如何处理调用进程屏蔽SIGALRM信号?
3、不允许出现任何竟态条件(时间窗口)。
4、总之,mysleep的实现细节应当对调用者透明,也就是说,不论在实现mysleep函数时是否使用了alarm函数,对调用者是否以及如何使用alarm函数均不应有任何影响。
三、实验分析过程
在mysleep函数中,用sigprocmask和sigsuspend来处理调用进程屏蔽SIGALRM信号。对于mysleep函数中的闹钟与调用者可能设置的闹钟之间的关系,在mysleep中检查第一次调用alarm的返回值,如其小于本次调用alarm的参数值,则应等到上次设置的闹钟超时。如果上次设置的闹钟的超时时间大于本次设置值,则在mysleep函数返回之前,复位次闹钟,使其在上次闹钟的设定时间再次发生超时。
四、实验程序
#include "apue.h"
static void sig_sleep(int signo)
{
}
static void sig_alrm(int signo)
{
printf("alarming~\n");
}
unsigned int mysleep (unsigned int nsecs)
{
structsigaction newact, oldact;
sigset_tnewmask, oldmask, suspmask, pendmask;
unsignedint uslept=0, already,temp,extra=0,equal=0,suspend_before_sleep=0,MASK_SIGALRM=0;
/*setour handler*/
newact.sa_handler= sig_sleep;
sigemptyset(&newact.sa_mask);
newact.sa_flags= 0;
sigaction(SIGALRM,&newact,&oldact);
if(sigpending(&pendmask)<0)
{
printf("pendmaskerror\n");
exit(1);
}
if(sigismember(&pendmask,SIGALRM))
{//thereis a SIGALRM suspend before sleep
suspend_before_sleep= 1;
}
/*blockSIGALRM and save signal mask*/
sigemptyset(&newmask);
sigaddset(&newmask,SIGALRM);
sigprocmask(SIG_BLOCK,&newmask,&oldmask);
if(sigismember(&oldmask,SIGALRM))
{//processmask SIGALRM
MASK_SIGALRM= 1;
}
/*doour work*/
already= alarm(nsecs);
if(already> 0 && already < nsecs)
{//Alarmbefore wake up;
if(MASK_SIGALRM== 0)
{
alarm(already);
uslept= nsecs - already;
}
else//屏蔽了sigalam
uslept= 0;
}
elseif(already > 0 && already > nsecs)
{//Alarmafter wake up;
extra= already - nsecs;
uslept= 0;
}
elseif (already > 0 && already == nsecs)
equal= 1;
//rememberadd alarm(uslept) at the end
/*waitfor any signal to be caught*/
suspmask= oldmask;
sigdelset(&suspmask,SIGALRM);
sigsuspend(&suspmask);//dealwith the SIGALRM before sleep
if(suspend_before_sleep== 1)
{
sigsuspend(&suspmask);
}
/*sleepwas interrupt*/
temp= alarm(0);
/*resetsignal action and mask*/
sigaction(SIGALRM,&oldact, NULL);
sigprocmask(SIG_SETMASK,&oldmask, NULL);
/*addextra alarm*/
if(temp== 0)
{
if(extra> 0)
alarm(extra);
//rebuildSIGALRM
elseif(equal == 1 || (already < nsecs && already!=0))
raise(SIGALRM);
}
elseif (temp > 0)
{//exceptioninterrupt by other signal
alarm(extra+ temp);//add extra alarm
uslept+= temp; //correct uslept
}
//rebuildSIGALRM
if(suspend_before_sleep== 1 ||(MASK_SIGALRM && already < nsecs))
raise(SIGALRM);
return(uslept);
}