diff options
-rw-r--r-- | lib/libc/gen/sleep.c | 68 | ||||
-rw-r--r-- | lib/libc/gen/usleep.c | 66 |
2 files changed, 117 insertions, 17 deletions
diff --git a/lib/libc/gen/sleep.c b/lib/libc/gen/sleep.c index 6b872f9..6a9800d 100644 --- a/lib/libc/gen/sleep.c +++ b/lib/libc/gen/sleep.c @@ -43,38 +43,87 @@ static char sccsid[] = "@(#)sleep.c 8.1 (Berkeley) 6/4/93"; #include "pthread_private.h" #endif +#ifndef _THREAD_SAFE +#ifndef USE_NANOSLEEP #define setvec(vec, a) \ vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0 -#if !defined(_THREAD_SAFE) && !defined(USE_NANOSLEEP) static int ringring; #endif static void sleephandler() { -#if !defined(_THREAD_SAFE) && !defined(USE_NANOSLEEP) +#ifndef USE_NANOSLEEP ringring = 1; #endif } +#endif /* _THREAD_SAFE */ unsigned int sleep(seconds) unsigned int seconds; { -#if defined(_THREAD_SAFE) || defined(USE_NANOSLEEP) +#ifdef _THREAD_SAFE struct timespec time_to_sleep; struct timespec time_remaining; - struct sigvec vec, ovec; if (seconds != 0) { time_to_sleep.tv_sec = seconds; time_to_sleep.tv_nsec = 0; - setvec(vec, sleephandler); - (void) sigvec(SIGALRM, &vec, &ovec); - /* XXX race here.. a SIGALRM right _now_ could be lost */ nanosleep(&time_to_sleep, &time_remaining); - (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0); + seconds = time_remaining.tv_sec; + if (time_remaining.tv_nsec > 0) + seconds++; /* round up */ + } + return (seconds); +#else +#if defined(USE_NANOSLEEP) + struct timespec time_to_sleep; + struct timespec time_remaining; + struct sigaction act, oact; + sigset_t mask, omask; + int alarm_blocked; + + if (seconds != 0) { + time_to_sleep.tv_sec = seconds; + time_to_sleep.tv_nsec = 0; + + /* Block SIGALRM while fiddling with it */ + sigemptyset(&mask); + sigaddset(&mask, SIGALRM); + sigprocmask(SIG_BLOCK, &mask, &omask); + + /* 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 timout. 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 */ seconds = time_remaining.tv_sec; if (time_remaining.tv_nsec > 0) seconds++; /* round up */ @@ -121,5 +170,6 @@ sleep(seconds) (void) sigsetmask(omask); (void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0); return 0; -#endif +#endif /* USE_NANOSLEEP */ +#endif /* _THREAD_SAFE */ } diff --git a/lib/libc/gen/usleep.c b/lib/libc/gen/usleep.c index 0f3e004..fa04989 100644 --- a/lib/libc/gen/usleep.c +++ b/lib/libc/gen/usleep.c @@ -48,42 +48,91 @@ static char sccsid[] = "@(#)usleep.c 8.1 (Berkeley) 6/4/93"; #define USPS 1000000 /* number of microseconds in a second */ #endif +#ifndef _THREAD_SAFE +#ifndef USE_NANOSLEEP #define setvec(vec, a) \ vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0 -#if !defined(_THREAD_SAFE) && !defined(USE_NANOSLEEP) static int ringring; #endif static void sleephandler() { -#if !defined(_THREAD_SAFE) && !defined(USE_NANOSLEEP) +#ifndef USE_NANOSLEEP ringring = 1; #endif } +#endif /* _THREAD_SAFE */ void usleep(useconds) unsigned int useconds; { -#if defined(_THREAD_SAFE) || defined(USE_NANOSLEEP) +#ifdef _THREAD_SAFE struct timespec time_to_sleep; struct timespec time_remaining; - struct sigvec vec, ovec; if (useconds) { time_to_sleep.tv_nsec = (useconds % 1000000) * 1000; time_to_sleep.tv_sec = useconds / 1000000; - setvec(vec, sleephandler); - (void) sigvec(SIGALRM, &vec, &ovec); do { nanosleep(&time_to_sleep, &time_remaining); time_to_sleep = time_remaining; } while (time_to_sleep.tv_sec != 0 && time_to_sleep.tv_nsec != 0); - (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0); + } +#else +#ifdef USE_NANOSLEEP + struct timespec time_to_sleep; + 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; + + /* Block SIGALRM while fiddling with it */ + sigemptyset(&mask); + sigaddset(&mask, SIGALRM); + sigprocmask(SIG_BLOCK, &mask, &omask); + + /* 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 timout. If the process blocks SIGALRM, it + * gets what it asks for. + */ + + do { + signanosleep(&time_to_sleep, &time_remaining, &mask); + time_to_sleep = time_remaining; + } while (time_to_sleep.tv_sec != 0 && + time_to_sleep.tv_nsec != 0); + + if (!alarm_blocked) { + /* Unwind */ + sigaction(SIGALRM, &oact, (struct sigaction *)0); + sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); + } } #else register struct itimerval *itp; @@ -125,5 +174,6 @@ usleep(useconds) (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0); (void) sigsetmask(omask); (void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0); -#endif +#endif /* USE_NANOSLEEP */ +#endif /* _THREAD_SAFE */ } |