diff options
Diffstat (limited to 'lib/libc/gen/sleep.c')
-rw-r--r-- | lib/libc/gen/sleep.c | 79 |
1 files changed, 70 insertions, 9 deletions
diff --git a/lib/libc/gen/sleep.c b/lib/libc/gen/sleep.c index 87aeb36..b3dd8b7 100644 --- a/lib/libc/gen/sleep.c +++ b/lib/libc/gen/sleep.c @@ -38,19 +38,80 @@ static char sccsid[] = "@(#)sleep.c 8.1 (Berkeley) 6/4/93"; #include <sys/time.h> #include <signal.h> #include <unistd.h> +#ifdef _THREAD_SAFE +#include <pthread.h> +#include "pthread_private.h" +#else + +#define setvec(vec, a) \ + vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0 + +static int ringring; +#endif unsigned int sleep(seconds) unsigned int seconds; { - struct timespec time_to_sleep; - struct timespec time_remaining; - - if (seconds != 0) { - time_to_sleep.tv_sec = seconds; - time_to_sleep.tv_nsec = 0; - nanosleep(&time_to_sleep, &time_remaining); - seconds = time_remaining.tv_sec; +#ifdef _THREAD_SAFE + struct timespec time_to_sleep; + struct timespec time_remaining; + + if (seconds) { + time_to_sleep.tv_sec = seconds; + time_to_sleep.tv_nsec = 0; + nanosleep(&time_to_sleep,&time_remaining); + seconds = time_remaining.tv_sec; + } + return(seconds); +#else + register struct itimerval *itp; + struct itimerval itv, oitv; + struct sigvec vec, ovec; + long omask; + static void sleephandler(); + + itp = &itv; + if (!seconds) + return 0; + timerclear(&itp->it_interval); + timerclear(&itp->it_value); + if (setitimer(ITIMER_REAL, itp, &oitv) < 0) + return seconds; + itp->it_value.tv_sec = seconds; + if (timerisset(&oitv.it_value)) { + if (timercmp(&oitv.it_value, &itp->it_value, >)) + oitv.it_value.tv_sec -= itp->it_value.tv_sec; + else { + itp->it_value = oitv.it_value; + /* + * This is a hack, but we must have time to return + * from the setitimer after the alarm or else it'll + * be restarted. And, anyway, sleep never did + * anything more than this before. + */ + oitv.it_value.tv_sec = 1; + oitv.it_value.tv_usec = 0; + } } - return (seconds); + setvec(vec, sleephandler); + (void) sigvec(SIGALRM, &vec, &ovec); + omask = sigblock(sigmask(SIGALRM)); + ringring = 0; + (void) setitimer(ITIMER_REAL, itp, (struct itimerval *)0); + while (!ringring) + sigpause(omask &~ sigmask(SIGALRM)); + (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0); + (void) sigsetmask(omask); + (void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0); + return 0; +#endif +} + +#ifndef _THREAD_SAFE +static void +sleephandler() +{ + ringring = 1; } +#endif |