C + UNIX,siglongjmp和sigsetjmp

时间:2013-12-18 01:01:14

标签: c linux unix system

我有一本来自(旧)教科书的程序,旨在说明在UNIX上使用POSIX信号。该程序运行一个计算循环来计算从固定点开始的完美数字。

  • 时间报警信号用于定期打印状态。
  • 中断信号用于按需状态。
  • 退出信号用于重置测试间隔(或终止)。

void perfect(int);

sigjmp_buf jmpenv; /* environment saved by setjmp*/

int n; /* global variable indicating current test point */

int main() {

    int begin; /* starting point for next search*/
        /* interrupt routines*/
    void status();
    void query();

    sigset_t mask;
    struct sigaction action;


    if (sigsetjmp(jmpenv,0)) {
        printf("Enter search starting point (0 to terminate): ");
        scanf("%d",&begin);
        if (begin==0) exit(0);
        sigprocmask(SIG_UNBLOCK, &mask, NULL);
        }
    else begin=2;

    /* Status Routine will handle timer and INTR */

    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);
    sigaddset(&mask, SIGALRM);
    sigaddset(&mask, SIGQUIT);
    action.sa_flags=0;
    action.sa_mask=mask;

    action.sa_handler=status;
    sigaction(SIGINT,&action,NULL);
    sigaction(SIGALRM,&action,NULL);

    action.sa_handler=query;
    sigaction(SIGQUIT,&action,NULL);

    /* start alarm clock */
    alarm(20);
    perfect(begin);
}

void perfect(start) 
    int start;
{
    int i,sum;

    n=start;

while (1) {
    sum=1;
    for (i=2;i<n;i++)
        if (!(n%i)) sum+=i;

    if (sum==n) printf("%d is perfect\n",n);
    n++;
    }
}

void status(signum) 
int signum;
{

    alarm(0); /* shutoff alarm */

    if (signum == SIGINT) printf("Interrupt ");
    if (signum == SIGALRM) printf("Timer ");

    printf("processing %d\n",n);

    alarm(20);  /*restart alarm*/
}   

void query() {siglongjmp(jmpenv,1);}

我的问题是:

  1. 为什么调用void status();和void query();在主要的第一个?
  2. 在if语句检查begin == 0并决定退出之后,它跟随一行名为“sigprocmask(SIG_UNBLOCK,&amp; mask,NULL);”我退出后为什么必须让它解锁?

1 个答案:

答案 0 :(得分:4)

  1. 这两行将函数status()query()声明为返回void。他们没有指定他们采取什么参数。在现代C中,在另一个函数中声明函数是一种诅咒(并且在没有完整原型的情况下声明它们也是诅咒 - 但这似乎是另一天的讨论,因为它不是你的代码)。函数应在其他函数之外声明,如果它们在另一个文件中定义或使用,则应在标题中声明它们。如果它们在当前文件中定义而未在任何其他文件中使用,则应声明它们并将其定义为static函数。

  2. 变量begin非正规初始化。第一次通过代码时设置为2;在从sigsetjmp()返回非零之后,它由用户输入设置。它也可能被setjmp()内容破坏,因为它没有标记为volatile。规则是深奥的。

    但是,意图是如果begin为零,则程序退出。否则,它将继续。 sigprocmask()旨在解锁任何被屏蔽的信号。我不清楚这是必要的。当您从信号处理程序返回时,即使您通过siglongjmp()退出,也应该取消阻止阻止的信号 -

  3. 请注意,在信号处理程序中调用printf()会调用未定义的行为。它可能会好,但不能保证。有一个可以调用的函数列表,可以在POSIX standard中或在SO上的其他问题中调用(我知道我之前已经给出了该列表)。


    仔细阅读这些功能的手册页:

    Chris Dodd sigsetjmp()且第二个参数为0的mask未保存当前信号掩码时,

    comments是正确的。请注意,setjmp()的值位于调用volatile后修改的局部变量中,并且未标记为setjmp(),因此setjmp()返回时的值为非零值是不确定的(请参阅sigsetjmp()手册页中的警告。)

    sig*手册页的基本原理部分是有趣的阅读,并提到类似的功能出现在4.2 BSD(1982年发布)中,所以我对70年代不存在的评论仍然有效(K&amp; R 1st版本和第7版UNIX™分别于1978年和1979年发布。 _setjmp()名称是AFAICT,由POSIX发明(BSD系统包括_longjmp()和{{1}})。