diff options
-rw-r--r-- | libc/unistd/sleep.c | 40 |
1 files changed, 18 insertions, 22 deletions
diff --git a/libc/unistd/sleep.c b/libc/unistd/sleep.c index 55e646380..481e635a2 100644 --- a/libc/unistd/sleep.c +++ b/libc/unistd/sleep.c @@ -50,6 +50,7 @@ unsigned int sleep (unsigned int seconds) { struct timespec ts = { .tv_sec = (long int) seconds, .tv_nsec = 0 }; sigset_t set; + struct sigaction oact; unsigned int result; /* This is not necessary but some buggy programs depend on this. */ @@ -62,33 +63,28 @@ unsigned int sleep (unsigned int seconds) /* Linux will wake up the system call, nanosleep, when SIGCHLD arrives even if SIGCHLD is ignored. We have to deal with it - in libc. We block SIGCHLD first. */ + in libc. */ + __sigemptyset (&set); __sigaddset (&set, SIGCHLD); - sigprocmask (SIG_BLOCK, &set, &set); /* never fails */ - /* If SIGCHLD was already blocked, no need to check SIG_IGN. Else... */ + /* Is SIGCHLD set to SIG_IGN? */ + sigaction (SIGCHLD, NULL, &oact); /* never fails */ + if (oact.sa_handler == SIG_IGN) { + /* Yes. Block SIGCHLD, save old mask. */ + sigprocmask (SIG_BLOCK, &set, &set); /* never fails */ + } + + /* Run nanosleep, with SIGCHLD blocked if SIGCHLD is SIG_IGNed. */ + result = nanosleep (&ts, &ts); + if (!__sigismember (&set, SIGCHLD)) { - struct sigaction oact; - - /* Is SIGCHLD set to SIG_IGN? */ - sigaction (SIGCHLD, NULL, &oact); /* never fails */ - if (oact.sa_handler == SIG_IGN) { - /* Yes, run nanosleep with SIGCHLD blocked. */ - result = nanosleep (&ts, &ts); - - /* Unblock SIGCHLD by restoring signal mask. */ - /* this sigprocmask call never fails, thus never updates errno, - and therefore we don't need to save/restore it. */ - sigprocmask (SIG_SETMASK, &set, NULL); - } else { - /* No workaround needed, unblock SIGCHLD by restoring signal mask. */ - sigprocmask (SIG_SETMASK, &set, NULL); - result = nanosleep (&ts, &ts); - } + /* We did block SIGCHLD, and old mask had no SIGCHLD bit. + IOW: we need to unblock SIGCHLD now. Do it. */ + /* this sigprocmask call never fails, thus never updates errno, + and therefore we don't need to save/restore it. */ + sigprocmask (SIG_SETMASK, &set, NULL); /* never fails */ } - else - result = nanosleep (&ts, &ts); if (result != 0) /* Round remaining time. */ |