@@ -1055,21 +1055,64 @@ static void pcntl_signal_handler(int signo)
1055
1055
/* oops, too many signals for us to track, so we'll forget about this one */
1056
1056
return ;
1057
1057
}
1058
- PCNTL_G (spares ) = psig -> next ;
1059
1058
1060
- psig -> signo = signo ;
1061
- psig -> next = NULL ;
1059
+ struct php_pcntl_pending_signal * psig_first = psig ;
1060
+
1061
+ /* Standard signals may be merged into a single one.
1062
+ * POSIX specifies that SIGCHLD has the si_pid field (https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html),
1063
+ * so we'll handle the merging for that signal.
1064
+ * See also: https://www.gnu.org/software/libc/manual/html_node/Merged-Signals.html */
1065
+ if (signo == SIGCHLD ) {
1066
+ /* Note: The first waitpid result is not necessarily the pid that was passed above!
1067
+ * We therefore cannot avoid the first waitpid() call. */
1068
+ int status ;
1069
+ pid_t pid ;
1070
+ while (true) {
1071
+ do {
1072
+ errno = 0 ;
1073
+ /* Although Linux specifies that WNOHANG will never result in EINTR, POSIX doesn't say so:
1074
+ * https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitpid.html */
1075
+ pid = waitpid (WAIT_ANY , & status , WNOHANG );
1076
+ } while (pid <= 0 && errno == EINTR );
1077
+ if (pid <= 0 ) {
1078
+ if (UNEXPECTED (psig == psig_first )) {
1079
+ /* Don't handle multiple, revert back to the single signal handling. */
1080
+ goto single_signal ;
1081
+ }
1082
+ break ;
1083
+ }
1084
+
1085
+ psig -> signo = signo ;
1062
1086
1063
1087
#ifdef HAVE_STRUCT_SIGINFO_T
1064
- psig -> siginfo = * siginfo ;
1088
+ psig -> siginfo = * siginfo ;
1089
+ psig -> siginfo .si_pid = pid ;
1065
1090
#endif
1066
1091
1092
+ if (EXPECTED (psig -> next )) {
1093
+ psig = psig -> next ;
1094
+ } else {
1095
+ break ;
1096
+ }
1097
+ }
1098
+ } else {
1099
+ single_signal :;
1100
+ psig -> signo = signo ;
1101
+
1102
+ #ifdef HAVE_STRUCT_SIGINFO_T
1103
+ psig -> siginfo = * siginfo ;
1104
+ #endif
1105
+ }
1106
+
1107
+ PCNTL_G (spares ) = psig -> next ;
1108
+ psig -> next = NULL ;
1109
+
1067
1110
/* the head check is important, as the tick handler cannot atomically clear both
1068
1111
* the head and tail */
1069
1112
if (PCNTL_G (head ) && PCNTL_G (tail )) {
1070
- PCNTL_G (tail )-> next = psig ;
1113
+ PCNTL_G (tail )-> next = psig_first ;
1071
1114
} else {
1072
- PCNTL_G (head ) = psig ;
1115
+ PCNTL_G (head ) = psig_first ;
1073
1116
}
1074
1117
PCNTL_G (tail ) = psig ;
1075
1118
PCNTL_G (pending_signals ) = 1 ;
0 commit comments