【问题标题】:Signal handling c programming信号处理 c 编程
【发布时间】:2013-11-19 14:18:05
【问题描述】:

我正在尝试学习 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" );
}

【问题讨论】:

    标签: c process operating-system signals


    【解决方案1】:

    通常,请参阅sigaction 的文档。

    具体来说,

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

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

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

    *为什么我们用一个handler函数初始化长格式的action.sa_sigaction,然后用另一个signal handler初始化action.sa_handler?*

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

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

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

    【讨论】:

    • 有趣的是,如果这个si_errno 永远是!= 0。可能在 Solaris 上?找不到关于这个的任何文档。
    • @flyer,我认为它通常是为“系统生成”信号设置的,比如 SIGBUS。
    猜你喜欢
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 2021-09-07
    • 1970-01-01
    • 2017-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多