linux 信号设计 --不断补充--欢迎指正讨论

Linux 信号产生条件:
1. 用户输入
2. 系统异常:浮点异常和非法内存段访问
3. 系统状态变化:比如alarm 定时器到期将引起SIGALRM信号
4. 运行kill 命令

1. 发送信号:
    int kill(pid_t pid, int sig);
   
   参数:
   pid = 0 信号发给本进程内的其他进程
   注意sig = 0情况,=0 表示不发送任何信号,用来检测进程或是进程组是否存在

   返回值:
   成功:0   失败:-1并设置errno

2. 进程在收到信号时,假如不想用系统默认的方式处理信号需要提前定义扑捉信号,并设置信号收到后的处理函数
2.1 扑捉信号:
     _sighandler_t signal(int sig, _sighandler_t _handler);

    参数:
    
    返回值:
    成功:    失败:返回SIG_ERR并设置errno

3   加强版的扑捉信号:在收到sig后,执行act.handler函数时,屏蔽act.sa_mask中的信号(在执行sig信号处理函数时,可能收到act.sa_mask的信息,为了避免不必要的中断,暂时屏蔽)
     int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);

     参数:
      sa_flags成员用于设置程序收到信号时的行为。
     SA_RESTART: 重新调用被该信号终止的系统调用
     SA_RESETHAND:信号处理函数执行完以后,恢复信号的默认处理方式

4.   信号处理函数:进程在收到信号之后,不是执行信号的默认动作,执行该函数
     信号处理函数原型:
     _sighandler_t signal(int sig, _sighandler_t _handler);
     
     参数:
     sig:扑捉到的信号
     
     返回值:
     返回SIG_DEF(假如是第一次调用signal) 或是 前一次调用signal函数时传入的函数指针


示例:
1. 扑捉信号
bcl_sig_sethandler( SIGTERM, bcl_signal_handle );

1.1 对扑捉函数sigation封装
Sigfunc  bcl_sig_sethandler( int signo, Sigfunc sighandler ) 
{
    struct sigaction sa, sav;

    sigemptyset( &sa.sa_mask );
    sigaddset( &sa.sa_mask, signo );
    sa.sa_handler = sighandler;
    sa.sa_flags = 0;                   //收到信号时的行为

    if ( signo == SIGALRM ) {
#ifdef SA_INTERRUPT
        sa.sa_flags |= SA_INTERRUPT;  //中断系统调用
#endif
    }
    else {
#ifdef SA_RESTART
        sa.sa_flags |= SA_RESTART;   //除了时钟信号需要中断系统调用,其他都恢复
#endif
    }

    if ( sigaction( signo, &sa, &sav ) < 0 ) {
        bclerreg( E_OSCALL, __FILE__, __LINE__, "sigaction()" );
        return SIG_ERR;
    }
    return sav.sa_handler; // signal函数返回上一次的传入signal函数的信号处理函数
}

1.2 信号处理函数
void  bcl_signal_handle( int sig ) 
{
    pid_t       cpid;
    int         flag;

    switch ( sig ) {
        case SIGALRM:
            if ( SIGALRMtrap != NULL ) {
                 signal( SIGALRM, bcl_signal_handle ); //再次扑捉
                (*SIGALRMtrap)();
             }
        break;
        case SIGURG:
        break;
#ifdef SIGEMT
        case SIGEMT:    /* EMT instruction */
#endif
        case SIGFPE:    /* floating point exception */
        case SIGBUS:    /* bus error */
        case SIGSEGV:   /* segmentation violation */
            fprintf( stderr, "Process[%d] recv signal[%d], coredump!!!\n", \
                              getpid(), sig );
            abort();  /*收到上面4个信号,都是退出,case后面都没有跟break*/

#ifdef SIGSYS
 case SIGSYS:    /* Bad argument to system call */
#endif
        case SIGPIPE:   /* Pipe broken */
        break;
        case SIGTERM:   /* software termination signal from kill */ 
            if ( SIGTERMtrap != NULL ) {
                (*SIGTERMtrap)();
                signal( SIGTERM, bcl_signal_handle );
            }
            else
                exit( 0 );
        case SIGUSR1:    /* 用户自定义信号 */
            if ( SIGUSR1trap != NULL )
                (*SIGUSR1trap)();
            signal( SIGUSR1, bcl_signal_handle );
            break;
        case SIGUSR2:   /* user defined signal 2 */
            sigusr2_flag = 1;
            if ( SIGUSR2trap != NULL )
                (*SIGUSR2trap)();
            signal( SIGUSR2, bcl_signal_handle );
            break;
        case SIGCHLD:  /*子进程退出,父进程会受到这个信号,需要父进程清理子进程资源*/
            while ( (cpid = waitpid(-1, &flag, WNOHANG)) > 0 ) {
                if ( SIGCLDtrap != NULL )
                    (*SIGCLDtrap)( cpid, flag );
            }
            signal( SIGCHLD, bcl_signal_handle );
            break;
    }
}

2. 对于阻塞的系统调用,加上errno的判断,效果等同在sigaction中设置恢复系统调用
for(;;)
{
    if ( (ret=recvmsg( sockfd, &msg, 0 )) <= 0 ) 
    {
        if ( errno == EINTR ) /*做判断,假如是因为系统调用,需要重新调用,假如系统     调用中有时间参数,需要重新计算阻塞时间*/
               continue;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值