LINUX.ORG.RU

Обработка сигнала в одной процедуре

 , ,


0

1

Привет лор. В общем есть процедура, допустим:

void
main () {
    int fd = open (...);

    signal (SIGINT, ...);
    
    for (;;) {
      /*
        какой-то код
      */
    }

clean:
    close (fd);
}

Нужно словить сигнал SIGINT, и перейти на метку clean. В общем не хочется создавать еще одну процедуру, делать дескриптор глобальным, и все ради одной малюсенькой инструкции. Что делать? Может можно как-то иначе подойти к этой задаче и я надмозг?

Может быть, можно как-то с setjmp/longjmp извратиться?

Deleted ()

В общем не хочется.. делать дескриптор глобальным

А какая разница, если «Use of this function is unspecified in a multi-threaded process.

И вообще: „The sigaction() function provides a more comprehensive and reliable mechanism for controlling signals; new applications should use sigaction() rather than signal()“

makoven ★★★★★ ()
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <setjmp.h>
#include <signal.h>

jmp_buf env;

void on_sigint(int sig) {
        longjmp(env, 1);
}

int main() {
        int fd = open("/dev/null", O_RDONLY);

        signal(SIGINT, on_sigint);

        if (setjmp(env))
                goto clean;

work:
        sleep(3);
        puts("timeout");

clean:
        puts("cleanup");
        close(fd);
}
Deleted ()
Последнее исправление: romeo250501 (всего исправлений: 1)

Может можно как-то иначе подойти к этой задаче

Конечно. Когда в процессе read прилетит сигнал, то read вернёт -1 и errno будет установлена в EINTR. Вот и всё:

    ssize_t ret;
    for (;;) {
        ret = read (fd, ...);
        if (ret == -1 && errno == EINTR)
            goto clean;
    }

gag ★★★★★ ()
Ответ на: комментарий от gag

аа, нет. read для примера что есть код, который выполняется в цикле. Поправил шапку.

chinarulezz ★★★★★ ()
Ответ на: комментарий от makoven

Use of this function is unspecified in a multi-threaded process

С чего ты взял, что у ОПа — multi-threaded process? Или ты думаешь, что signal handler выполняется в отдельном потоке? Нет.

anonymous ()

А теперь ещё немного акробатики:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

int main(int argc, char *argv[])
    {
    static int signaled = 0;
    static int volatile interrupted = 0;
    struct sigaction sa;
    int i = 0;

    if(signaled)
        {
        interrupted = 1;
        return 0;
        }

    sa.sa_handler = (void (*)(int))main;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    sigaction(SIGINT, &sa, NULL);

    signaled = 1;

    for(;;)
        {
        fprintf(stderr, "Waiting: %d\r", i++);
        sleep(1);

        if(interrupted)
            goto clean;
        }

    clean:

    fprintf(stderr,"\nCleanup\n");

    return 0;
    }
cdslow ()

Можно заблокировать сигнал и проверять его появление в цикле:

#include <signal.h>

int main(void)
{
   sigset_t set;
   sigemptyset(&set);
   sigaddset(&set, SIGINT);
   sigprocmask(SIG_BLOCK, &set, NULL);
   for (;;) {
      /*
        какой-то код
      */
      sigpending(&set);
      if (sigismember(&set, SIGINT)))
         goto clean;
   }

clean:
    close (fd);
}

x-signal ()

А Я бы посоветовал signalfd. Он даст тебе еще один дескриптор для чтения, и можешь в том же цикле его читать. Это бывает довольно удобно для всяких event-based хотелок.

joy4eg ★★★★★ ()
Ответ на: комментарий от joy4eg
#include <sys/signalfd.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#define handle_error(msg) \
    do { perror(msg); exit(EXIT_FAILURE); } while (0)

int
main(int argc, char *argv[])
{
    sigset_t mask;
    int sfd;
    struct signalfd_siginfo fdsi;
    ssize_t s;

    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);
    sigaddset(&mask, SIGQUIT);

    /* Block signals so that they aren't handled
       according to their default dispositions */

    if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
        handle_error("sigprocmask");

    sfd = signalfd(-1, &mask, 0);
    if (sfd == -1)
        handle_error("signalfd");

    for (;;) {
        s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
        if (s != sizeof(struct signalfd_siginfo))
            handle_error("read");

        if (fdsi.ssi_signo == SIGINT) {
            printf("Got SIGINT\n");
        } else if (fdsi.ssi_signo == SIGQUIT) {
            printf("Got SIGQUIT\n");
            exit(EXIT_SUCCESS);
        } else {
            printf("Read unexpected signal\n");
        }
    }
}

joy4eg ★★★★★ ()
Ответ на: комментарий от chinarulezz

sa.sa_handler = (void (*)(int))main;

Это приведение типов. main из int (*fn)(int argc, char *argv[]) в нужный для sa_handler тип, который void (*sa_handler)(int).

joy4eg ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.