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).
Das Problem ist, dass die Funktion signal()
zwei unterschiedliche Verhaltensweisen beim Installieren einer Signalverarbeitungsfunktion haben kann:
SIG_DFL
zurückgesetzt - und System-Aufrufe, die vom Signal unterbrochen werden, nicht neu gestartet; oder 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.
Diese subtilen Verhaltensunterschiede sind der Grund, warum sigprocmask()
normalerweise vor signal()
steht. Die Version mit _XOPEN_SOURCE 700
definierten Aufrufen (wie von strace gezeigt)
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.