X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=lib%2Fnanosleep.c;h=fe22a97cabac69e955e2c10c6575e71e571f4716;hb=0785c73b8869fdb3f3cadbd5d180e84b2e827be3;hp=7ffe05d2eb39cccbd8527f4c470b0eb4f8ac4fdf;hpb=c7d932558714df7c297f28f644d5cc45e9a42e23;p=gnulib.git diff --git a/lib/nanosleep.c b/lib/nanosleep.c index 7ffe05d2e..fe22a97ca 100644 --- a/lib/nanosleep.c +++ b/lib/nanosleep.c @@ -19,9 +19,7 @@ /* written by Jim Meyering */ -#ifdef HAVE_CONFIG_H -# include -#endif +#include /* Undefine nanosleep here so any prototype is not redefined to be a prototype for rpl_nanosleep. (they'd conflict e.g., on alpha-dec-osf3.2) */ @@ -29,10 +27,10 @@ #include #include +#include #if HAVE_SYS_SELECT_H # include #endif -#include #include #if TIME_WITH_SYS_TIME @@ -52,16 +50,74 @@ #include "timespec.h" +enum { BILLION = 1000 * 1000 * 1000 }; + +#if HAVE_BUG_BIG_NANOSLEEP + +void +getnow (struct timespec *t) +{ +# if defined CLOCK_MONOTONIC && HAVE_CLOCK_GETTIME + if (clock_gettime (CLOCK_MONOTONIC, t) == 0) + return; +# endif + gettime (t); +} + +int +rpl_nanosleep (const struct timespec *requested_delay, + struct timespec *remaining_delay) +{ + /* nanosleep mishandles large sleeps due to internal overflow + problems, so check that the proper amount of time has actually + elapsed. */ + + struct timespec delay = *requested_delay; + struct timespec t0; + getnow (&t0); + + for (;;) + { + int r = nanosleep (&delay, remaining_delay); + if (r == 0) + { + time_t secs_sofar; + struct timespec now; + getnow (&now); + + secs_sofar = now.tv_sec - t0.tv_sec; + if (requested_delay->tv_sec < secs_sofar) + return 0; + delay.tv_sec = requested_delay->tv_sec - secs_sofar; + delay.tv_nsec = requested_delay->tv_nsec - (now.tv_nsec - t0.tv_nsec); + if (delay.tv_nsec < 0) + { + if (delay.tv_sec == 0) + return 0; + delay.tv_nsec += BILLION; + delay.tv_sec--; + } + else if (BILLION <= delay.tv_nsec) + { + delay.tv_nsec -= BILLION; + delay.tv_sec++; + } + } + } +} + +#else + /* Some systems (MSDOS) don't have SIGCONT. Using SIGTERM here turns the signal-handling code below into a no-op on such systems. */ -#ifndef SIGCONT -# define SIGCONT SIGTERM -#endif +# ifndef SIGCONT +# define SIGCONT SIGTERM +# endif -#if ! HAVE_SIGINTERRUPT -# define siginterrupt(sig, flag) /* empty */ -#endif +# if ! HAVE_SIGINTERRUPT +# define siginterrupt(sig, flag) /* empty */ +# endif static sig_atomic_t volatile suspended; @@ -107,7 +163,7 @@ rpl_nanosleep (const struct timespec *requested_delay, /* set up sig handler */ if (! initialized) { -#ifdef SA_NOCLDSTOP +# ifdef SA_NOCLDSTOP struct sigaction oldact, newact; newact.sa_handler = sighandler; sigemptyset (&newact.sa_mask); @@ -116,13 +172,13 @@ rpl_nanosleep (const struct timespec *requested_delay, sigaction (SIGCONT, NULL, &oldact); if (oldact.sa_handler != SIG_IGN) sigaction (SIGCONT, &newact, NULL); -#else +# else if (signal (SIGCONT, SIG_IGN) != SIG_IGN) { signal (SIGCONT, sighandler); siginterrupt (SIGCONT, 1); } -#endif +# endif initialized = true; } @@ -143,3 +199,4 @@ rpl_nanosleep (const struct timespec *requested_delay, return suspended; } +#endif