#include <unistd.h>
#include <signal.h>
#include <stdio.h>
void sig_alrm(int signo) {
NULL; //nothing to do
}
unsigned int mysleep(unsigned int nsecs) { ////gdb单步调试时显示为14,查头文件bits/signum.h为SIGALRM
struct sigaction newact, oldact;
unsigned int unslept;
//在内核注册SIGALRM信号的处理函数sig_alrm
newact.sa_handler = sig_alrm;
//初始化sa_mask所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含任何有效信号。
//当某个信号的处理函数被调用时候,当前的信号被加入到进程的信号阻塞集,如果想让其他信号也加入到信号阻塞集合就通过sa_mask来说明。
sigemptyset(&newact.sa_mask);
newact.sa_flags = 0;
//通过传入newact修改了SIGALRM信号的处理动作,传入oldact读取SIGALRM原来的处理动作
sigaction(SIGALRM, &newact, &oldact); //把SIGALRM对应的编号传入信号处理注册函数(sig_alrm)的参数列表中。
alarm(nsecs); //在当前进程设定闹钟,时间一到就终止当前进程
//调用pause等待,内核切换到别的进程进行了。
pause(); //将进程挂起,直到有信号抵达
/*
*(信号在内核产生,如果阻塞的话也是阻塞在内核,从内核到用户空间的过程中,
*信号都属于未决信号,进入到用户空间[不执行main的上下文,而是执行信号处理
*函数的控制流程。]调用sighandler函数时属于信号抵达)
*调用了pause,进程就挂起了,nsecs秒之后,闹钟超时,内核发SIGALRM给这个进程
*然后从内核态准备返回。但在从内核态返回到这个进程的用户态之前要处理未决信号,
*发现有SIGALRM信号,其处理函数是sig_alrm。这时,切换到用户态执行sig_alrm
*函数(信号抵达),进入sig_alrm函数时SIGALRM信号被自动屏蔽(当调用信号处理
*函数时,当前信号被自动加入到当前进程的信号阻塞集)从sig_alrm函数返回时,
*SIGALRM信号自动杰出屏蔽。然后自动执行系统调用sigreturn再次进入内核,
*再返回用户态继续执行进程的主控制流程(main函数调用的mysleep函数),也就
*是恢复到main函数的上下文。pause函数返回-1(因为执行了sighandle函数),然后
*调用alarm(0)取消闹钟,调用sigaction还原SIGALRM信号以前的处理动作.
*/
unslept = alarm(0);
printf("remain seconds(unslept): %d\n", unslept);
sigaction(SIGALRM, &oldact, NULL);
return unslept;
}
int main(void) {
while(1) {
mysleep(2);
printf("two sconds passed\n");
}
return 0;
}