Hi, The 13th patch caters to unavailability of wait3() system call on older SYSV systems such as UnixPC. On these systems, only an always blocking wait() is available. In order to get non-blocking wait, you have to use a SIGCLD handler (not a typo, child signal handling on SYSV was subtly different from what we are used to now). This handler sets a flag (gotsigchld) when a child dies. When upper layers request a non-blocking wait, we test for this flag. If the gotsigchld flag is set, we can wait(), confident in the knowledge that this call will return right away. Then clear the flag, and re-instore SIGCLD handler. If the gotsigchld flag is not set, we return right away with 0 ("process does have children, but none have exited so far") The "subtle difference" between SIGCLD and SIGCHLD is that SIGCLD is "level triggered": i.e. the system continues raising the signal as long as there is a terminated child around on which the parent has not yet waited. Thus, SIGCLD should not be re-enabled in the handler, but only after wait() https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xsh_chap02.html "Some implementations (System V, for example) will deliver a SIGCLD signal immediately when a process establishes a signal-catching function for SIGCLD when that process has a child that has already terminated. Other implementations, such as 4.3 BSD, do not generate a new SIGCHLD signal in this way. In general, a process should not attempt to alter the signal action for the SIGCHLD signal while it has any outstanding children. However, it is not always possible for a process to avoid this; for example, shells sometimes start up processes in pipelines with other processes from the pipeline as children. Processes that cannot ensure that they have no children when altering the signal action for SIGCHLD thus need to be prepared for, but not depend on, generation of an immediate SIGCHLD signal." Actually, in a way we do "depend on" this peculiarity to implement non-blocking wait(). However, if it is not available, the only thing that breaks is "monitor mode" (notification of terminated children when pressing return in an interactive shell). Edit: contrarily to what I had announced this morning, there's no amendment needed here after all. I was misled by a wrong configure invocation line for dietlibc, which somehow led to #include files being included out of order Regards, Alain diff -X ../exclude.txt -urN dash-0.5.12+12-sigaction/configure.ac dash-0.5.12+13-wait3-replacement/configure.ac --- dash-0.5.12+12-sigaction/configure.ac 2024-11-10 17:08:01.155025888 +0000 +++ dash-0.5.12+13-wait3-replacement/configure.ac 2024-11-10 20:26:19.105474215 +0000 @@ -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) diff -X ../exclude.txt -urN dash-0.5.12+12-sigaction/src/jobs.c dash-0.5.12+13-wait3-replacement/src/jobs.c --- dash-0.5.12+12-sigaction/src/jobs.c 2024-10-27 20:19:13.625231580 +0000 +++ dash-0.5.12+13-wait3-replacement/src/jobs.c 2024-11-10 21:51:55.911519696 +0000 @@ -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); diff -X ../exclude.txt -urN dash-0.5.12+12-sigaction/src/system.h dash-0.5.12+13-wait3-replacement/src/system.h --- dash-0.5.12+12-sigaction/src/system.h 2024-11-10 16:26:47.464166999 +0000 +++ dash-0.5.12+13-wait3-replacement/src/system.h 2024-11-10 14:53:08.418618090 +0000 @@ -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 diff -X ../exclude.txt -urN dash-0.5.12+12-sigaction/src/trap.c dash-0.5.12+13-wait3-replacement/src/trap.c --- dash-0.5.12+12-sigaction/src/trap.c 2024-11-10 20:26:44.222071158 +0000 +++ dash-0.5.12+13-wait3-replacement/src/trap.c 2024-11-10 20:27:41.055421903 +0000 @@ -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;