2

我正在尝试学习 C 编程中的信号,但我很难理解一些概念。我有这个代码可用,我希望有人能指导我完成它。我主要是想了解main()长格式和短格式之间的区别。

  1. 长格式有什么作用SA_SIGINFO | SA_RESTART;
  2. 为什么我们使用一个处理函数以action.sa_sigaction长格式初始化,然后使用另一个信号处理函数进行初始化action.sa_handler
#include    <errno.h>
#include    <math.h>
#include    <stdlib.h>
#include    <signal.h>
#include    <stdio.h>
#include    <unistd.h>
#include    <sys/time.h>
#include    "printBlocked.h"

// Timer demonstration of signal handling.  Timer intervals are random.

static int
bkr_random( int lo, int hi )
{
    static int  seed = 2*3*5*7*11*13*17*19+1;
    static int  prime = 2*3*5*7*11*13*17+1;
    int     value;

    value = lo + (seed>>3) % (hi-lo+1);
    seed *= prime;
    seed = seed < 0 ? -seed : seed;
    return value;
}

static void
timeout_handler( int signo, siginfo_t * info , void * p )
{
    struct itimerval    interval;

    printf( "timeout_handler() invoked.  errno is %d\n", info->si_errno );
    printBlocked( "timeout handler" );
    interval.it_interval.tv_usec = 0;               /* No repeat interval */
    interval.it_interval.tv_sec = 0;
    interval.it_value.tv_sec = 0;
    interval.it_value.tv_usec = 25000 * bkr_random( 1, 39 );    /* reset interval each time */
    setitimer( ITIMER_REAL, &interval, 0 );
}

static void
signal_handler( int signo )
{
    switch ( signo )
    {
        case SIGINT:
            printf( "Signal handler invoked.  Delivered signal is %s.\n", _sys_siglist[signo] );
            printBlocked( "signal handler" );
            exit( 0 );
            break;
        case SIGWINCH:
            system( "clear" );
            printf( "Signal handler invoked.  Window size changed.\n" );
            printBlocked( "signal handler" );
            break;
        default:
            printf( "Signal handler invoked.  unknown signal delivered is %s.\n", _sys_siglist[signo] );
            printBlocked( "signal handler" );
            break;
    }
}

int
main()
{
    struct sigaction    action;
    struct itimerval    interval;

    printf( "main() invoked in process %d.\n", getpid() );
    printBlocked( "main()" );

    action.sa_flags = SA_SIGINFO | SA_RESTART;  /* asking for long form and abilty to continue normal execution */
    action.sa_sigaction = timeout_handler;      /* long form */
    sigemptyset( &action.sa_mask );         /* no additional signals blocked */
    sigaction( SIGALRM, &action, 0 );

    action.sa_flags = 0;
    action.sa_handler = signal_handler;     /* short form */
    sigemptyset( &action.sa_mask );         /* no additional signals blocked */
    sigaction( SIGINT, &action, 0 );
    sigaction( SIGWINCH, &action, 0 );

    interval.it_interval.tv_sec = 0;                /* No repeat interval */
    interval.it_interval.tv_usec = 0;
    interval.it_value.tv_usec = 25000 * bkr_random( 1, 39 );    /* initial interval */
    interval.it_value.tv_sec = 0;
    setitimer( ITIMER_REAL, &interval, 0 );

    while( pause() == -1 );             /* wait for a signal, any signal */
    printf( "Normal end.\n" );
}
4

1 回答 1

4

通常,请参阅sigaction.

具体来说,

SA_SIGINFO | 什么是 SA_重新启动;长篇大论?

SA_SIGINFO 告诉系统调用“长格式”处理程序sa_sigaction而不是“短格式”处理程序sa_handler

SA_RESTART 告诉系统在从信号处理程序返回时重新启动某些系统调用。否则,这些调用通常会因 errno 设置为 EINTR 而失败。无论是否设置了 SA_SIGINFO,这都适用。

*为什么我们使用一个处理函数来初始化长格式的action.sa_sigaction,然后使用另一个信号处理函数来初始化action.sa_handler?*

sa_sigaction通常在需要siginfo_t传入额外信息时使用。在这种情况下,您展示的代码的作者想知道什么 errno 与信号生成 ( si_errno) 相关联。现在,在我的系统上,该字段在显示的代码中始终为零——没有与我们自己设置的警报相关联的 errno,也没有从外部传递(如通过kill(1)命令)。

其他信号操作不需要额外的信息,因此使用更简单的sa_handler界面没有害处。

(顺便说一句,良好的信号处理实践将处理程序限制为调用异步信号安全的函数。您发布的代码不会这样做。)

于 2013-11-07T20:53:57.927 回答