-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I see no reason why we can't sleep for more than 49.7 days (not that I
expect many programs to try that, though).  Plus, sleep was reading
uninitialized memory, giving garbage answers.

Here's an example that proves where this matters:
$ (time timeout 2 sleep 49d) 2>&1 | grep sys
sys     0m0.046s
$ (time timeout 2 sleep 50d) 2>&1 | grep sys
sys     0m1.500s

Notice how CPU utilization spikes from nearly 0% to nearly 100% once you
cross 49.7 days, because sleep(1) is now in a super-tight loop of
repeatedly calling nanosleep (which fails), then checking the current time
to see if enough elapsed time has occurred.

2009-11-18  Eric Blake  <[email protected]>

        * signal.cc (nanosleep): Support 'infinite' sleep times.
        (sleep): Avoid uninitialized memory.

- --
Don't work too hard, make some time for fun as well!

Eric Blake             [email protected]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAksEVYEACgkQ84KuGfSFAYCcFgCfU2rkcgCAQ4Ywfv73mJe51AbL
xZsAnRwuA/ybkXvz+3uEQvUzyHjbWk4l
=pH2l
-----END PGP SIGNATURE-----
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, [email protected]
    Significant changes by Sergey Okhapkin <[email protected]>
@@ -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

Reply via email to