12、信号(2)

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);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值