diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/gen/sleep.c | 48 | ||||
-rw-r--r-- | lib/libc/gen/usleep.c | 48 |
2 files changed, 58 insertions, 38 deletions
diff --git a/lib/libc/gen/sleep.c b/lib/libc/gen/sleep.c index 485f778..b553bf7 100644 --- a/lib/libc/gen/sleep.c +++ b/lib/libc/gen/sleep.c @@ -87,6 +87,7 @@ sleep(seconds) struct timespec time_remaining; struct sigaction act, oact; sigset_t mask, omask; + int alarm_blocked; if (seconds != 0) { /* @@ -102,30 +103,39 @@ sleep(seconds) time_to_sleep.tv_sec = seconds; time_to_sleep.tv_nsec = 0; - /* - * Set up handler to interrupt signanosleep and ensure - * SIGARLM is not blocked. Block SIGALRM while fiddling - * with things. - */ - memset(&act, 0, sizeof(act)); - act.sa_handler = sleephandler; + /* Block SIGALRM while fiddling with it */ sigemptyset(&mask); sigaddset(&mask, SIGALRM); sigprocmask(SIG_BLOCK, &mask, &omask); - sigaction(SIGALRM, &act, &oact); - mask = omask; - sigdelset(&mask, SIGALRM); - /* - * signanosleep() uses the given mask for the lifetime of - * the syscall only - it resets on return. Note that the - * old sleep explicitly unblocks SIGALRM during the sleep. - */ - signanosleep(&time_to_sleep, &time_remaining, &mask); + /* Was SIGALRM blocked already? */ + alarm_blocked = sigismember(&omask, SIGALRM); - /* Unwind */ - sigaction(SIGALRM, &oact, (struct sigaction *)0); - sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); + if (!alarm_blocked) { + /* + * Set up handler to interrupt signanosleep only if + * SIGALRM was unblocked. (Save some syscalls) + */ + memset(&act, 0, sizeof(act)); + act.sa_handler = sleephandler; + sigaction(SIGALRM, &act, &oact); + } + + /* + * signanosleep() uses the given mask for the lifetime of + * the syscall only - it resets on return. Note that the + * old sleep() explicitly unblocks SIGALRM during the sleep, + * we don't do that now since we don't depend on SIGALRM + * to end the timeout. If the process blocks SIGALRM, it + * gets what it asks for. + */ + signanosleep(&time_to_sleep, &time_remaining, &omask); + + if (!alarm_blocked) { + /* Unwind */ + sigaction(SIGALRM, &oact, (struct sigaction *)0); + sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); + } /* return how long is left */ rest += time_remaining.tv_sec; diff --git a/lib/libc/gen/usleep.c b/lib/libc/gen/usleep.c index c8e26cb..85c75a4 100644 --- a/lib/libc/gen/usleep.c +++ b/lib/libc/gen/usleep.c @@ -76,42 +76,52 @@ usleep(useconds) struct timespec time_remaining; struct sigaction act, oact; sigset_t mask, omask; + int alarm_blocked; if (useconds != 0) { time_to_sleep.tv_nsec = (useconds % 1000000) * 1000; time_to_sleep.tv_sec = useconds / 1000000; - /* - * Set up handler to interrupt signanosleep and ensure - * SIGARLM is not blocked. Block SIGALRM while fiddling - * with things. - */ - memset(&act, 0, sizeof(act)); - act.sa_handler = sleephandler; + /* Block SIGALRM while fiddling with it */ sigemptyset(&mask); sigaddset(&mask, SIGALRM); sigprocmask(SIG_BLOCK, &mask, &omask); - sigaction(SIGALRM, &act, &oact); - mask = omask; - sigdelset(&mask, SIGALRM); + alarm_termination = 0; - /* - * signanosleep() uses the given mask for the lifetime of - * the syscall only - it resets on return. Note that the - * old sleep explicitly unblocks SIGALRM during the sleep. - */ + /* Was SIGALRM blocked already? */ + alarm_blocked = sigismember(&omask, SIGALRM); + + if (!alarm_blocked) { + /* + * Set up handler to interrupt signanosleep only if + * SIGALRM was unblocked. (Save some syscalls) + */ + memset(&act, 0, sizeof(act)); + act.sa_handler = sleephandler; + sigaction(SIGALRM, &act, &oact); + } + /* + * signanosleep() uses the given mask for the lifetime of + * the syscall only - it resets on return. Note that the + * old sleep() explicitly unblocks SIGALRM during the sleep, + * we don't do that now since we don't depend on SIGALRM + * to end the timeout. If the process blocks SIGALRM, it + * gets what it asks for. + */ do { - signanosleep(&time_to_sleep, &time_remaining, &mask); + signanosleep(&time_to_sleep, &time_remaining, &omask); time_to_sleep = time_remaining; } while (!alarm_termination && (time_to_sleep.tv_sec != 0 || time_to_sleep.tv_nsec != 0)); - /* Unwind */ - sigaction(SIGALRM, &oact, (struct sigaction *)0); - sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); + if (!alarm_blocked) { + /* Unwind */ + sigaction(SIGALRM, &oact, (struct sigaction *)0); + sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); + } } #endif /* _THREAD_SAFE */ } |