XOPEN_SOURCE und Signalverarbeitung

8

Wenn ich im folgenden Programm _XOPEN_SOURCE -Zeile auskommentiere, wird mein Programm beendet, wenn ich C-c drücke, das gleiche Programm wird nicht beendet Wenn ich diese Zeile nicht kommentiere. Jeder weiß, auf welche Weise sich _XOPEN_SOURCE auf die Signalverarbeitung auswirkt. Ich bin auf Linux mit Gcc (4.6.3) und Glibc (2.15).

%Vor%     
yasar 23.05.2012, 07:11
quelle

2 Antworten

4

Das Problem ist, dass die Funktion signal() zwei unterschiedliche Verhaltensweisen beim Installieren einer Signalverarbeitungsfunktion haben kann:

  • System-V-Semantik, bei der der Signal-Handler "one-shot" ist, dh nachdem die Signal-Handling-Funktion aufgerufen wurde, wird die Disposition des Signals auf SIG_DFL zurückgesetzt - und System-Aufrufe, die vom Signal unterbrochen werden, nicht neu gestartet; oder
  • BSD-Semantik, bei der der Signal-Handler nicht zurückgesetzt wird, wenn das Signal ausgelöst wird, das Signal während der Ausführung des Signal-Handlers blockiert wird und die meisten unterbrochenen Systemaufrufe automatisch neu gestartet werden.

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

Wenn der read() -Systemaufruf % getchar() unter System V-Semantik unterbrochen wird, gibt SIGINT getchar() mit EOF auf errno zurück (dies wird Ihr Programm dazu veranlassen, normal verlassen). Zusätzlich wird nach dem ersten EINTR die Disposition dieses Signals auf den Standardwert zurückgesetzt, und die Standardaktion für SIGINT besteht darin, den Prozess zu beenden (also selbst wenn Ihr Programm den ersten SIGINT überlebte, würde der zweite verursachen es abnormal zu beenden).

Die Lösung besteht darin, SIGINT nicht für die Installation von Signalverarbeitungsfunktionen zu verwenden. Stattdessen sollten Sie signal() verwenden, das ist portabel - es gibt überall dieselbe Semantik. Wenn sigaction() auf sa_flags , SA_RESTART gesetzt ist, gibt es die BSD-Semantik, was Sie wollen.

    
caf 23.05.2012, 07:38
quelle
1

Diese subtilen Verhaltensunterschiede sind der Grund, warum sigprocmask() normalerweise vor signal() steht. Die Version mit _XOPEN_SOURCE 700 definierten Aufrufen (wie von strace gezeigt)

%Vor%

Während die auskommentierte Person ruft:

%Vor%

Das wichtige zusätzliche Flag, das _XOPEN_SOURCE fehlt, ist SA_RESTART , was dem read Systemaufruf erlaubt weiterzumachen, als ob kein Signal aufgetreten wäre. Ohne diesen gibt der Systemaufruf einen Fehler an, getchar() gibt -1 zurück (zeigt aber einen Fehler anstelle eines echten EOF an), und Ihr Programm wird beendet.

    
Dave 23.05.2012 07:47
quelle

Tags und Links