Messages in this thread | | | Date | Mon, 27 Oct 2014 04:01:44 +0000 | From | Pádraig Brady <> | Subject | nanosleep truncated on 64 bit Linux by 292 billion years |
| |
I noticed that nanosleep() on 64 bit, "only" supports 292 years, rather than the full potential 292 billion years with 64 bit time_t, due to: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/linux/time.h?id=refs/tags/v3.16#n87
Attached is a program from Paul Eggert that illustrates the bug. Running this program on a buggy host outputs something like this:
Setting alarm for 1 second from now ... Sleeping for 9223372036854775807.999999999 seconds... After alarm sent off, remaining time is 9223357678.462306617 seconds; i.e., nanosleep claimed that it slept for about 293079448610.606445 years.
Gnulib-using applications have a workaround for this bug, but a workaround shouldn't be necessary. For what it's worth, the bug is fixed in Solaris 11 (x86-64), though it's present in Solaris 10 (64-bit sparc).
thanks, Pádraig. #include <time.h> #include <errno.h> #include <limits.h> #include <stdio.h> #include <signal.h> #include <unistd.h>
static void check_for_SIGALRM (int sig) { if (sig != SIGALRM) _exit (1); }
int main (void) { static struct sigaction act; struct timespec forever, remaining; time_t time_t_max = (1ull << (sizeof time_t_max * CHAR_BIT - 1)) - 1; act.sa_handler = check_for_SIGALRM; sigemptyset (&act.sa_mask); sigaction (SIGALRM, &act, NULL); forever.tv_sec = time_t_max; forever.tv_nsec = 999999999; printf ("Setting alarm for 1 second from now ...\n"); alarm (1); printf ("Sleeping for %lld.%09ld seconds...\n", (long long) forever.tv_sec, forever.tv_nsec); if (nanosleep (&forever, &remaining) == 0) return 2; if (errno != EINTR) return 3; if (remaining.tv_sec < time_t_max - 10) { printf ("After alarm sent off, remaining time is %lld.%09ld seconds;\n", (long long) remaining.tv_sec, remaining.tv_nsec); printf ("i.e., nanosleep claimed that it slept for about %f years.\n", (forever.tv_sec - remaining.tv_sec) / (24 * 60 * 60 * 364.2425)); return 4; } printf ("ok\n"); return 0; }
| |