Обработчик сигнала для SIGALRM не работает, даже если сброс в обработчике - PullRequest
2 голосов
/ 01 ноября 2009

Пример кода из раздела 10.6, ожидаемый результат:
после нескольких итераций статическая структура, используемая getpwnam, будет повреждена, и программа завершит работу с сигналом SIGSEGV.

Но на моей платформе, Fedora 11, gcc (GCC) 4.4.0, результат равен

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

Я могу видеть вывод из 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);
}

Ответы [ 3 ]

7 голосов
/ 01 ноября 2009

В соответствии со стандартом, вы действительно не можете делать многое в обработчике сигналов. Все, что вы гарантированно сможете сделать в функции обработки сигналов, не вызывая неопределенного поведения, - это вызвать signal и присвоить значение энергозависимому статическому объекту типа sig_atomic_t .

Первые несколько раз, когда я запускал эту программу в Ubuntu Linux, выглядело, как будто ваш вызов alarm в обработчике сигналов не работал, поэтому цикл в main просто продолжал работать после первого сигнала тревоги , Когда я попробовал это позже, программа несколько раз запускала обработчик сигнала, а затем зависала. Все это согласуется с неопределенным поведением: иногда происходит сбой программы, а также различными более или менее интересными способами.

Нередко программы с неопределенным поведением по-разному работают в отладчике. Отладчик - это другая среда, и ваша программа и данные могут, например, быть размещены в памяти по-другому, поэтому ошибки могут проявляться по-другому, или не проявляться вовсе.

Я заставил программу работать, добавив переменную:

volatile sig_atomic_t got_interrupt = 0;

А потом я изменил ваш обработчик сигналов на этот очень простой:

void sig_alarm(int signo) {
    got_interrupt = 1;
}

А затем я вставил фактическую работу в бесконечный цикл в 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);
}

Я думаю, что "apue", о котором вы говорите, это книга "Расширенное программирование в среде UNIX", которой у меня нет, поэтому я не знаю, если цель этого примера - показать, что вы не должны не возиться с вещами внутри обработчика сигналов или просто с тем, что сигналы могут вызвать проблемы, нарушая нормальную работу программы.

1 голос
/ 29 марта 2013
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void sigalrm_handler(int);




int main()
{   
    signal(SIGALRM, sigalrm_handler);

    alarm(3);   


    while(1)
    {

    }

    return 0;
}


void sigalrm_handler(int sign)
{   

    printf("I am alive. Catch the sigalrm %d!\n",sign);
    alarm(3);
}

Например, мой код работает в основном, ничего не делая, и каждые 3 секунды моя программа говорит, что я жива x)

Я думаю, что если вы сделаете так, как я, вызвав в функции обработчика сигнал тревоги со значением 3, проблема решится:)

1 голос
/ 02 ноября 2009

Согласно спецификации, функция getpwnam не является реентерабельной и не гарантируется поточно-ориентированной Поскольку вы обращаетесь к структуре в двух разных потоках управления (обработчики сигналов эффективно работают в другом контексте потока), вы столкнулись с этой проблемой. Всякий раз, когда у вас есть параллельное или параллельное выполнение (как при использовании pthreads или при использовании обработчика сигнала), вы должны быть уверены, что не изменили совместно используемое состояние (например, структуру, принадлежащую 'getpwnam'), и если вы это сделаете, то соответствующая блокировка / синхронизация должен быть использован.

Кроме того, функция сигнала устарела в пользу функции sigaction . Чтобы обеспечить переносимость при регистрации обработчиков сигналов, всегда следует использовать вызов sigaction .

Используя функцию sigaction, вы можете использовать флаг SA_RESETHAND для сброса обработчика по умолчанию. Вы также можете использовать функцию sigprocmask для включения / отключения доставки сигналов без изменения их обработчиков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...