1、信号被屏蔽后无法捕获,但是没有消失,5s后恢复则立即捕获到
#include "apue.h"
static void sig_quit(int);
int main(void)
{
sigset_t newmask, oldmask, pendmask;
if(signal(SIGQUIT, sig_quit)==SIG_ERR)
err_sys("can't catch SIGQUIT");
sigemptyset(&newmask);
sigaddset(&newmask, SIGQUIT);
if(sigprocmask(SIG_BLOCK, &newmask, &oldmask)<0)
err_sys("SIG_BLOCK ERROR");
sleep(5);
if(sigpending(&pendmask)<0)
err_sys("sigpending error");
if(sigismember(&pendmask, SIGQUIT))
printf("\nSIGQUIT pending\n");
if(sigprocmask(SIG_SETMASK, &oldmask, NULL)<0)
err_sys("SIG_SETMASK ERROR");
printf("SIGQUIT unblocked\n");
sleep(5);
exit(0);
}
static void sig_quit(int signo)
{
printf("caught SIGQUIT\n");
// if(signal(SIGQUIT,SIG_DFL)==SIG_ERR)
// err_sys("can't catch SIGQUIT");
}
2、sigsetjmp、siglongjmp
siglongjmp会跳转到sigsetjmp继续执行,
#include <setjmp.h>
//第二个参数非0,则进程当前信号屏蔽字会保存到env中
//直接调用该函数返回0,从siglongjmp调用返回,则返回非0
int sigsetjmp(sigjmp_buf env, int savemask);
//如果sigsetjmp已经保存了env,则setlongjmp从其中恢复信号屏蔽字
void siglongjmp(sigjmp_buf env, int val);
//使用全局标志canjump的目的是当sigsetjmp初始化后才能调用信号处理程序
//SIGUSR1信号处理程序中,3秒后发送ALARM信号,5秒后在SIGUSR1信号处理程序中中回调到main
//sig_atomic_t 由IS0 C定义的变量,在写这类变量时不会被中断
#include "apue.h"
#include <setjmp.h>
#include <time.h>
#include "prmask.c"
static void sig_usr1(int);
static void sig_alrm(int signo);
static sigjmp_buf jmpbuf;
static volatile sig_atomic_t canjump;
int main(void)
{
signal(SIGUSR1, sig_usr1);
signal(SIGALRM, sig_alrm);
pr_mask("starting main:");
if(sigsetjmp(jmpbuf,1)){
pr_mask("ending main:");
exit(0);
}
canjump=1;
for(;;)
pause();
}
static void sig_alrm(int signo)
{
pr_mask("in sig_alrm:");
}
static void sig_usr1(int signo)
{
time_t starttime;
if(canjump == 0)
return;
pr_mask("starting sig_usr1: ");
alarm(3);
starttime = time(NULL);
for(; ;)
if(time(NULL) > starttime + 5)
break;
pr_mask("finishing sig_usr1:");
canjump = 0;
siglongjmp(jmpbuf, 1);
}
3、sigsuspend
先把进程信号屏蔽字设为sigmask的值,再挂起进程。
捕捉到信号并从信号处理程序返回,该函数也返回,且恢复调用该函数之前的信号屏蔽字。
int sigsuspend(const sigset_t *sigmask);
//屏蔽了SIGUSR1信号
#include "apue.h"
#include "prmask.c"
static void sig_int(int);
int main(void)
{
sigset_t newmask, oldmask, waitmask;
pr_mask("program start:");
signal(SIGINT, sig_int);
sigemptyset(&waitmask);
sigaddset(&waitmask, SIGUSR1);
sigemptyset(&newmask);
sigaddset(&newmask, SIGINT);
if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
err_sys("SIG_BLOCK error");
pr_mask("in critical region:");
if(sigsuspend(&waitmask) != -1)
err_sys("sigsuspend error");
pr_mask("after return from sigsuspend:");
if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err_sys("SIG_SETMASK error");
pr_mask("program exit:");
exit(0);
}
static void sig_int(int signo)
{
pr_mask("\n in sig_int:");
}
4、abort
让进程捕捉SIGABRT的意图是:在进程终止之前由其执行所需的清理操作
//使程序异常终止(将SIGABRT信号发送给进程)
void abort(void);
void abort(void)
{
sigset_t mask;
struct sigaction action;
//由action返回之前动作
sigaction(SIGABRT, NULL, &action);
if(action.sa_handler == SIG_IGN){
action.sa_handler = SIG_DFL;
sigaction(SIGABRT,&action, NULL);
}
if(action.sa_handler == SIG_DFL)
fflush(NULL);
sigfillset(&mask);
sigdelset(*mask, SIGABRT);
sigprocmask(SIG_SETMASK, &mask, NULL);
kill(getpid(), SIGABRT);
//进程捕获了信号并返回,此时进程可能产生了更多的输出,所以再一次冲洗所有的流。
fflush(NULL);
action.sa_handler = SIG_DFL;
sigaction(SIGABRT,&action, NULL);
sigprocmask(SIG_SETMASK, &mask, NULL);
kill(getpid(), SIGABRT);
exit(1);
}
5、system
执行之前的system的过程如下。键入中断符会把中断信号发送给前台进程组中所有进程。为使只有子进程处理中断信号,而父进程忽略中断和退出转换system的实现方式
int main()
{
system("/bin/ed")
}
int system(const char *cmdstring)
{
pid_t pid;
int status;
struct sigaction ignore, saveintr, savequit;
sigset_t chldmask, savemask;
if(cmdstring == null)
return(1);
//设置中断和退出为忽略处理
ignore.sa_handler=SIG_IGN;
sigemptyset(&ignore.sa_mask);
ignore.sa_flag=0;
sigaction(SIGINT, &ignore, &saveintr);
sigaction(SIGQUIT, &ignore, &savequit);
//阻塞SIGVHLD信号
sigemptyset(&chldmask);
sigaddset(&chldmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
if((pid =fork()) < 0)
status = -1;
else if(pid == 0){
//子进程中恢复这些信号的处理
sigaction(SIGINT, &saveintr, NULL);
sigaction(SIGQUIT, &savequit, NULL);
sigprocmask(SIG_SETMASK, &savemask, NULL);
execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
_exit(127);
}else{
while(waitpid(pid, &status, 0) < 0){
if(errno != EINTR){
status = -1;
break;
}
}
}
}
sigaction(SIGINT, &saveintr, NULL);
sigaction(SIGQUIT, &savequit, NULL);
sigprocmask(SIG_SETMASK, &savemask, NULL);
return(status);
6、sleep、nanosleep
nanosleep提供纳秒级精度
进程被挂起直到满足下面条件之一返回
(1)已近过了指定时间
(2)调用进程捕获到一个信号并从信号处理程序返回
unsigned int sleep(unsigned int seconds);
//reqtp用秒和纳秒指定休眠时间,若中断可以用remtp返回未休眠完的时间
int nanosleep(const struct timespec *reqtp, struct timespec *remtp);
//clock_id指定时钟类型,flags指定是绝对时间还是相对时间
int clock_nanosleep(clock_t clock_id, int flags, const struct timespec *reqtp, struct timespec *remtp)
7、sigqueue
支持信号排队,则需要sigcation函数安装信号处理程序时指定SA_SIGINFO标志。sigqueue类似kill函数,value参数向信号处理程序传递整数和指针值。
int sigqueue(pid_t pid, int signo, const union sigval value);
8、信号名和编号
数组下标是信号编号,数组中的元素是指向信号名的指针
extern char *sys_siglist[];
//返回编号对应字符串
void psignal(int signo, const char *msg);
char *strsignal(int signo);