@@ -117,7 +117,7 @@
mempcpy memmove \
sigsetmask stpcpy strchrnul strsignal strtod strtoimax \
strtoumax sysconf \
- vfork sigaction sigprocmask lstat dup2 getgroups \
+ vfork wait3 sigaction sigprocmask lstat dup2 getgroups \
strstr stpncpy strcasecmp strerror strdup strtoul vsnprintf \
readdir)
@@ -1154,6 +1154,50 @@
return rpid;
}
+#ifndef HAVE_WAIT3
+
+# ifndef WNOHANG
+# define WNOHANG 1
+# endif
+
+/* Replacement wait3 */
+STATIC inline pid_t
+wait3(int *wstatus, int options, void * rusage)
+{
+ pid_t pid;
+
+ /* if we are called as non-blocking, and have no SIGCLD
+ pending, return */
+ if((options & WNOHANG) && !gotsigchld)
+ return 0; /* 0 is returned by wait3 if the process does have
+ * children, but none have exited so far */
+ pid = wait(wstatus);
+ if(pid <= 0)
+ /* no process reaped, or error */
+ return pid;
+
+
+ /* if we come here, we did indeed reap a process. =>
+ * clear gotsigchld, and re-instore SIGCLD handler.
+ *
+ * On old SYSV systems where there is no wait3 call,
+ * signal(SIGCLD) is level-triggered, and will trigger as
+ * long as there are still unwaited-for children
+ * around. However, it is, like all other signals, disabled as
+ * soon as its signal handler is invoked, which prevents storm
+ * :-). So we need to re-enable it after wait(), in order to
+ * be notified of further children dying.
+ *
+ * If more than one child had died since last reset of
+ * gotsigchld, a signal will be delivered immediately after
+ * re-activation of the signal, because it is level-triggered.
+ */
+ gotsigchld = 0;
+ setsignal(SIGCLD);
+ return pid;
+}
+#endif
+
/*
* Do a wait system call. If block is zero, we return -1 rather than
* blocking. If block is DOWAIT_WAITCMD, we return 0 when a signal
@@ -1182,7 +1226,15 @@
#endif
do {
+#ifdef HAVE_WAIT3
+ /* reset gotsigchld *only* if we are not using a
+ * replacement wait3(). Indeed, the replacement
+ * wait3() needs original value of gotsigchld in order
+ * to decide whether it does indeed need to
+ * wait. Replacement wait3 will then reset gotsigchld
+ * when done with it */
gotsigchld = 0;
+#endif
do
err = wait3(status, flags, NULL);
while (err < 0 && errno == EINTR && !pending_sig);
@@ -159,6 +159,10 @@
# define O_NONBLOCK O_NDELAY
#endif
+#if !defined SIGCHLD && defined SIGCLD
+# define SIGCHLD SIGCLD
+#endif
+
#ifndef FD_CLOEXEC
# define FD_CLOEXEC 1
#endif
@@ -53,6 +53,7 @@
#include "error.h"
#include "trap.h"
#include "mystring.h"
+#include "system.h"
/*
* Sigmode records the current value of the signal handlers for the various
@@ -87,6 +88,7 @@
#ifdef mkinit
INCLUDE "memalloc.h"
INCLUDE "trap.h"
+INCLUDE "system.h"
INIT {
sigmode[SIGCHLD - 1] = S_DFL;
@@ -302,7 +304,10 @@
onsig(int signo)
{
#ifndef HAVE_SIGACTION
- signal(signo, onsig);
+#ifdef SIGCLD
+ if(signo != SIGCLD)
+#endif
+ signal(signo, onsig);
#endif
if (vforked)
return;