即使在处理程序中重置,SIGALRM的信号处理程序也不起作用

OnT*_*Way 2 c linux signals

第10.6节的示例代码,预期结果是:
在几次迭代之后,getpwnam使用的静态结构将被破坏,程序将以SIGSEGV信号终止.

但在我的平台上,Fedora 11,gcc(GCC)4.4.0,结果是

[Langzi @ Freedom apue] sig_alarm
中$ ./corrupt

我只能看到sig_alarm一次输出,程序似乎因某种原因而挂起,但它确实存在,并且仍在运行.
但是当我尝试使用gdb来运行程序时,似乎没问题,我会sig_alarm定期看到输出.

从我的手册中可以看出,在处理完信号后,信号处理程序将被设置为SIG_DEF,系统不会阻塞信号.所以在我的信号处理程序的开头,我重置了信号处理程序.

也许我应该使用sigaction,但我只想知道正常运行和gdb运行之间差异的原因.

任何建议和帮助将不胜感激.

以下是我的代码:

#include "apue.h"
#include <pwd.h>

void sig_alarm(int signo);

int main()
{
  struct passwd *pwdptr;
  signal(SIGALRM, sig_alarm);

  alarm(1);
  for(;;) {
    if ((pwdptr = getpwnam("Zhijin")) == NULL)
      err_sys("getpwnam error");
    if (strcmp("Zhijin", pwdptr->pw_name) != 0) {
      printf("data corrupted, pw_name: %s\n", pwdptr->pw_name);
    }
  }
}

void sig_alarm(int signo)
{
  signal(SIGALRM, sig_alarm);
  struct passwd *rootptr;
  printf("in sig_alarm\n");

  if ((rootptr = getpwnam("root")) == NULL)
    err_sys("getpwnam error");
  alarm(1);
}
Run Code Online (Sandbox Code Playgroud)

Tho*_*thy 7

根据标准,你真的不允许在信号处理程序中做很多事情.保证能够在信号处理功能中完成所有操作,而不会导致未定义的行为,是调用信号,并为sig_atomic_t类型的易失性静态对象赋值.

我在Ubuntu Linux上运行这个程序的前几次,看起来你在信号处理程序中调用警报不起作用,所以main中的循环在第一次警报后继续运行.当我稍后尝试时,程序运行了几次信号处理程序,然后挂起.所有这些都与未定义的行为一致:程序有时失败,并且以各种或多或少有趣的方式失败.

具有未定义行为的程序在调试器中以不同方式工作的情况并不少见.调试器是一个不同的环境,例如,您的程序和数据可以以不同的方式布局在内存中,因此错误可以以不同的方式表现出来,或者根本不表现出来.

我通过添加变量让程序工作:

volatile sig_atomic_t got_interrupt = 0;
Run Code Online (Sandbox Code Playgroud)

然后我将你的信号处理程序改为这个非常简单的处理程序:

void sig_alarm(int signo) {
    got_interrupt = 1;
}
Run Code Online (Sandbox Code Playgroud)

然后我将实际工作插入main中的无限循环:

if (got_interrupt) {
    got_interrupt = 0;
    signal(SIGALRM, sig_alarm);
    struct passwd *rootptr;
    printf("in sig_alarm\n");

    if ((rootptr = getpwnam("root")) == NULL)
        perror("getpwnam error");
    alarm(1);
}
Run Code Online (Sandbox Code Playgroud)

我认为你提到的"apue"是"UNIX环境下的高级编程"这本书,我在这里没有,所以我不知道这个例子的目的是否表明你不应该乱搞对信号处理程序内部的事物,或只是信号可能通过中断程序的正常工作导致问题.