8 Stimmen

XOPEN_SOURCE und Signalverarbeitung

Wenn ich in dem folgenden Programm das Kommentarzeichen _XOPEN_SOURCE Zeile, bricht mein Programm ab, wenn ich auf C-c Wenn ich diese Zeile nicht auskommentiere, wird das gleiche Programm nicht beendet. Weiß jemand, auf welche Weise das _XOPEN_SOURCE die Signalverarbeitung beeinflussen? Ich bin auf linux mit gcc (4.6.3) und glibc (2.15).

/* #define _XOPEN_SOURCE 700 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

typedef void (*sighandler_t)(int);

void handle_signal(int signo)
{
    printf("\n[MY_SHELL] ");
    fflush(stdout);
}

int main()
{
    int c;
    signal(SIGINT, SIG_IGN);
    signal(SIGINT, handle_signal);
    printf("[MY_SHELL] ");
    while ((c = getchar()) != EOF) {
        if (c == '\n')
            printf("[MY_SHELL] ");
    }
    printf("\n");
    return 0;
}

4voto

caf Punkte 224189

Das Problem ist, dass die signal() Funktion kann sich bei der Installation einer Signalverarbeitungsfunktion auf zwei verschiedene Arten verhalten:

  • System-V-Semantik, bei der der Signalbehandler "einmalig" ist, d. h. nach dem Aufruf der Signalbehandlungsfunktion wird die Disposition des Signals wieder auf SIG_DFL - und Systemaufrufe, die durch das Signal unterbrochen werden, werden nicht neu gestartet; oder
  • BSD-Semantik, bei der der Signalhandler no zurückgesetzt, wenn das Signal ausgelöst wird, wird das Signal blockiert, während der Signalhandler ausgeführt wird, und die meisten unterbrochenen Systemaufrufe werden automatisch neu gestartet.

Unter Linux mit glibc erhalten Sie die BSD-Semantik, wenn _BSD_SOURCE definiert ist, und die System-V-Semantik, wenn sie nicht definiert ist. Die _BSD_SOURCE Makro ist standardmäßig definiert, aber diese Standarddefinition wird unterdrückt, wenn Sie _XOPEN_SOURCE (oder auch ein paar andere Makros, wie _POSIX_SOURCE y _SVID_SOURCE ).

Unter der System-V-Semantik, wenn die read() zugrundeliegender Systemaufruf getchar() wird unterbrochen durch SIGINT dann getchar() wird zurückgegeben EOF con errno eingestellt auf EINTR (dadurch wird Ihr Programm normal beendet). Außerdem wird nach der ersten SIGINT wird die Disposition dieses Signals auf den Standardwert zurückgesetzt, und die Standardaktion für SIGINT ist es, den Prozess zu beenden (also selbst wenn Ihr Programm die erste SIGINT die zweite würde zu einem abnormalen Abbruch führen).

Die Lösung besteht darin, nicht zu verwenden signal() für die Installation von Signalverarbeitungsfunktionen zu verwenden; stattdessen sollten Sie sigaction() die portabel ist, d.h. überall die gleiche Semantik bietet. Mit sa_flags eingestellt auf SA_RESTART , sigaction() wird es die BSD-Semantik geben, die Sie wollen.

1voto

Dave Punkte 10698

Diese subtilen Verhaltensunterschiede sind der Grund dafür sigprocmask() wird in der Regel vorgezogen gegenüber signal() Die Version mit _XOPEN_SOURCE 700 definierte Aufrufe (wie von strace angezeigt)

rt_sigaction(SIGINT, {SIG_IGN, [], SA_INTERRUPT|SA_NODEFER|SA_RESETHAND}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGINT, {0x80484dc, [], SA_INTERRUPT|SA_NODEFER|SA_RESETHAND}, {SIG_IGN, [], SA_INTERRUPT|SA_NODEFER|SA_RESETHAND}, 8) = 0

Während der Auskommentierte anruft:

rt_sigaction(SIGINT, {SIG_IGN, [INT], SA_RESTART}, {SIG_DFL, [], 0}, 8) = 0 
rt_sigaction(SIGINT, {0x80484dc, [INT], SA_RESTART}, {SIG_IGN, [INT], SA_RESTART}, 8) = 0

Das wichtige zusätzliche Kennzeichen, das _XOPEN_SOURCE fehlt ist SA_RESTART die es ermöglicht, die read Systemaufruf, um fortzufahren, als ob kein Signal aufgetreten wäre. Andernfalls zeigt der Systemaufruf einen Fehler an, getchar() gibt zurück. -1 (aber mit dem Hinweis auf einen Fehler und nicht auf ein echtes EOF), und Ihr Programm wird beendet.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X