This is the mail archive of the cygwin-patches mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

patch: sleep/nanosleep bug


-----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  <ebb9@byu.net>

	* 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             ebb9@byu.net
-----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, sac@cygnus.com
    Significant changes by Sergey Okhapkin <sos@prospect.com.ru>
@@ -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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]