信号【5】-理解sigsuspend


前言

提示:要解决以下问题:

  1. sigsuspend使用的场景
  2. sigsuspend的实质

一、sigsuspend的应用场景

  • 临时阻塞一个信号,以防止其中断正在执行的关键代码
  • 解除对该信号的阻塞,然后暂停执行,直至有信号的传递

二、sigsuspend的实质

int sigsuspend(const sigset_t *mask);

调用sigsuspend()相当于以不可中段的方式执行以下操作:
sigprocmask(SIG_SETMASK,&mask,&prevMask); /*调整新的掩码*/
pause()
/*挂起之后再执行的信号处理函数*/
sigprocmask(SIG_SETMASK,&prevMask,NULL)

那我们写一段程序测试是否相当于执行以上代码。

  • 向执行sigsuspend(SIGUSER1)的进程发送siguser1的信号,是否可以执行指定的信号处理器。
#define __GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>

static volatile sig_atomic_t gotSigquit  =0;

void printSigset(FILE *of, const char *prefix, const sigset_t *sigset)
{
    int sig,cnt;
    cnt = 0;
    for (sig = 1; sig < NSIG; sig++){
        if (sigismember(sigset,sig)){
            cnt++;
            fprintf(of, "%s%d (%s)\n",prefix,sig,strsignal(sig));
        }
    }
    if (cnt == 0)
        fprintf(of, "%s < empty signal set >\n",prefix);
}

int printSigMask(FILE *of, const char *msg)
{
    sigset_t currMask;
    if (msg != NULL){
        fprintf(of, "%s",msg);
    }

    sigprocmask(SIG_BLOCK,NULL,&currMask);
    printSigset(of,"\t\t", &currMask);
}

int printPendingSigs(FILE *of, const char *msg)
{   
    sigset_t pendingSigs;
    if (msg != NULL)
        fprintf(of,"%s",msg);
    if (sigpending(&pendingSigs) == -1)
        return -1;

    printSigset(of,"\t\t",&pendingSigs);
    return 0;
}

static void handler(int sig)
{
    printf("caught signl %d,%s\n",sig,strsignal(sig)); /*unsafe*/
    if (sig == SIGQUIT)
        gotSigquit = 1;
}

int main(int argc, char **argv)
{
    int loopNum;
    time_t startTime;
    sigset_t origMask,blockMask;
    struct sigaction sa;
    
    printSigMask(stdout, "Initial signal mask is:\n");
    sigemptyset(&blockMask);
    sigaddset(&blockMask,SIGQUIT);
    sigaddset(&blockMask,SIGINT);
    if (sigprocmask(SIG_BLOCK, &blockMask,&origMask) == -1)
        exit(1);
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sa.sa_handler = handler;
    if (sigaction(SIGINT,&sa, NULL) == -1){
        exit(1);
    }

    if (sigaction(SIGQUIT,&sa,NULL) == -1)
        exit(1);
    
    for (loopNum = 1; !gotSigquit; loopNum++){
        printf("===LOOP %d\n",loopNum);
        /*假设一段关键代码的执行*/
        printSigMask(stdout, "Staring critical section,signal mask is :\n");
        for (startTime = time(NULL); time(NULL) < startTime + 4;){
            continue; /*运行几秒钟*/
        }

        printPendingSigs(stdout,"before sigsuspend() - pending signals:\n");
        if (sigsuspend(&origMask) == -1 && errno != EINTR)
        {
            exit(1);
        }
    }

    if (sigprocmask(SIG_SETMASK, &origMask,NULL) == -1)
        exit(1);
    
    printSigMask(stdout, "==Exited loop\n Restored signal mask to: \n");

    exit(1);
}

>>> a.out 
Initial signal mask is:
                 < empty signal set >

===LOOP 1
Staring critical section,signal mask is :
                2 (Interrupt)
                3 (Quit)
^C SIGINT 处于阻塞状态
before sigsuspend() - pending signals:
                2 (Interrupt)
caught signl 2,Interrupt

/*本身SIGINT处于阻塞状态,不应该显示caught signl 2,Interrupt,但是调用了sigsuspend 解除了SIGINT,*/
/*(执行了信号处理函数,但是因为sigsupend执行是解除阻塞挂起是原子操作,所以不会出现假死现象*/
===LOOP 2
Staring critical section,signal mask is :
                2 (Interrupt)
                3 (Quit)
^\before sigsuspend() - pending signals:
                3 (Quit)
caught signl 3,Quit
==Exited loop
 Restored signal mask to: 
                 < empty signal set >

总结

  • 这种问题的实质仍然是,信号传递的时机是:
    • 进程再调度超时后,再次获得调度时,即一个时间片的开始处
    • 系统调用完成时。
  • suspend的实质就是确保信号的传递是在系统调用完成时,进入系统调用检测是否有未决信号,防止不能叫醒自己。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值