diff options
author | Denys Vlasenko <dvlasenk@redhat.com> | 2010-10-22 15:22:40 +0200 |
---|---|---|
committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-10-22 15:22:40 +0200 |
commit | 62fb840ea00d9d10446959d290d93a45065220f4 (patch) | |
tree | e6a31f6d248a40613fb5926793d5367513488f5f | |
parent | f53db356f53686cb0e4ddb25946b8cff9e82453d (diff) |
sleep: check "SIGCHLD is SIG_IGN'ed" first. Saves two syscalls in common case
text data bss dec hex filename
- 197 0 0 197 c5 libc/unistd/sleep.o
+ 168 0 0 168 a8 libc/unistd/sleep.o
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
-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. */ |