diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index b3654de..4f248bf 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -1,7 +1,7 @@ /* signal.cc Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007, 2008 Red Hat, Inc. + 2005, 2006, 2007, 2008, 2009 Red Hat, Inc. Written by Steve Chamberlain of Cygnus Support, sac@cygnus.com Significant changes by Sergey Okhapkin @@ -87,14 +87,40 @@ nanosleep (const struct timespec *rqtp, struct timespec *rmtp) sig_dispatch_pending (); pthread_testcancel (); - if ((unsigned int) rqtp->tv_sec > (HIRES_DELAY_MAX / 1000 - 1) - || (unsigned int) rqtp->tv_nsec > 999999999) + if ((unsigned int) rqtp->tv_nsec > 999999999) { set_errno (EINVAL); return -1; } + /* FIXME - needs help if we ever decide to support 64-bit time_t. */ + time_t sec = rqtp->tv_sec; + while ((unsigned int) sec > (HIRES_DELAY_MAX / 1000 - 1)) + { + /* Too big for a single transaction. Repeatedly sleep for + smaller chunks (49.7 days at a time!) until either we get + EINTR or we have slept as long as the user requested + (supposing the universe hasn't burned out yet). */ + struct timespec temp = { HIRES_DELAY_MAX / 1000 - 1, 0 }; + int result = nanosleep (&temp, &temp); + sec -= HIRES_DELAY_MAX / 1000 - 1; + if (result) + { + if (rmtp) + { + rmtp->tv_sec = sec + temp.tv_sec; + rmtp->tv_nsec = rqtp->tv_nsec + temp.tv_nsec; + if (rmtp->tv_nsec >= 1000000000) + { + rmtp->tv_sec++; + rmtp->tv_nsec -= 1000000000; + } + } + return result; + } + } + DWORD resolution = gtod.resolution (); - DWORD req = ((rqtp->tv_sec * 1000 + (rqtp->tv_nsec + 999999) / 1000000 + DWORD req = ((sec * 1000 + (rqtp->tv_nsec + 999999) / 1000000 + resolution - 1) / resolution) * resolution; DWORD end_time = gtod.dmsecs () + req; syscall_printf ("nanosleep (%ld)", req); @@ -126,8 +152,9 @@ sleep (unsigned int seconds) struct timespec req, rem; req.tv_sec = seconds; req.tv_nsec = 0; - nanosleep (&req, &rem); - return rem.tv_sec + (rem.tv_nsec > 0); + if (nanosleep (&req, &rem)) + return rem.tv_sec + (rem.tv_nsec > 0); + return 0; } extern "C" unsigned int @@ -136,7 +163,7 @@ usleep (useconds_t useconds) struct timespec req; req.tv_sec = useconds / 1000000; req.tv_nsec = (useconds % 1000000) * 1000; - int res = nanosleep (&req, 0); + int res = nanosleep (&req, NULL); return res; } -- 1.6.4.2