bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: usleep (was: pending patches?)


From: Eric Blake
Subject: Re: usleep (was: pending patches?)
Date: Wed, 18 Nov 2009 19:19:10 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

Eric Blake <ebb9 <at> byu.net> writes:

> I'm pushing this.  Most systems these days still support usleep, even
> though POSIX no longer requires it; even mingw has it; so the few
> platforms where this implementation rounds up to the ceiling of the next
> second should be rare (still correct behavior, just slow).  And there is
> still a benefit to using usleep instead of select or nanosleep - fewer
> dependencies on external libraries.

On cygwin, sleep() and usleep() are based on nanosleep(); but cygwin 1.5.x that 
has a limit of 49.7 days (UINT_MAX milliseconds), and sleep additionally had a 
bug in that it returned garbage.  I have a patch pending for cygwin 1.7 that 
removes both the 49.7 day limitation and the sleep bug, but this fixes things 
for cygwin 1.5.x.  usleep was immune (it caps out at the 32-bit imposed limit 
of 4295 seconds).  And the nanosleep module was already detecting the cygwin 
limitation, although I have not stepped through the nanosleep.c code closely 
enough to know if it was also successfully working around the limitation.

Not a showstopper for the coreutils 8.1 release.


From: Eric Blake <address@hidden>
Date: Wed, 18 Nov 2009 12:02:19 -0700
Subject: [PATCH] sleep: work around cygwin bug

In cygwin 1.5.x, sleep(UINT_MAX/1000) returns immediately, sets
errno to EINVAL, and has a bogus return value from reading
uninitialized memory.  Although sleeping for more than 49.7 days
is rare, it is not unthinkable.  nanosleep had the same maximum
limit, but at least did not return garbage, and the gnulib wrapper
was already working around that limitation.

* lib/sleep.c (rpl_sleep): Work around cygwin 1.5.x bug.
* m4/sleep.m4 (gl_FUNC_SLEEP): Detect the bug.
(gl_PREREQ_SLEEP): Delete unused macro.
* m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Add default.
* modules/unistd (Makefile.am): Substitute witness.
* lib/unistd.in.h (sleep): Update prototype.
* doc/posix-functions/sleep.texi (sleep): Document the bug.
* doc/posix-functions/nanosleep.texi (nanosleep): Likewise.
* tests/test-sleep.c (main) [HAVE_DECL_ALARM]: Test it.
* modules/sleep-tests (Depends-on): Check for alarm.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog                          |   14 +++++++++++++
 doc/posix-functions/nanosleep.texi |    3 ++
 doc/posix-functions/sleep.texi     |    3 ++
 lib/sleep.c                        |   26 +++++++++++++++++++++++-
 lib/unistd.in.h                    |    6 ++++-
 m4/sleep.m4                        |   37 ++++++++++++++++++++++++++++++-----
 m4/unistd_h.m4                     |    3 +-
 modules/sleep-tests                |    1 +
 modules/unistd                     |    1 +
 tests/test-sleep.c                 |   24 +++++++++++++++++++++-
 10 files changed, 106 insertions(+), 12 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 12d789d..7a86a20 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2009-11-18  Eric Blake  <address@hidden>
+
+       sleep: work around cygwin bug
+       * lib/sleep.c (rpl_sleep): Work around cygwin 1.5.x bug.
+       * m4/sleep.m4 (gl_FUNC_SLEEP): Detect the bug.
+       (gl_PREREQ_SLEEP): Delete unused macro.
+       * m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Add default.
+       * modules/unistd (Makefile.am): Substitute witness.
+       * lib/unistd.in.h (sleep): Update prototype.
+       * doc/posix-functions/sleep.texi (sleep): Document the bug.
+       * doc/posix-functions/nanosleep.texi (nanosleep): Likewise.
+       * tests/test-sleep.c (main) [HAVE_DECL_ALARM]: Test it.
+       * modules/sleep-tests (Depends-on): Check for alarm.
+
 2009-11-17  Eric Blake  <address@hidden>

        stdlib-safer: preserve cloexec flag for mkostemp[s]
diff --git a/doc/posix-functions/nanosleep.texi b/doc/posix-
functions/nanosleep.texi
index a44ffa7..f4f0b56 100644
--- a/doc/posix-functions/nanosleep.texi
+++ b/doc/posix-functions/nanosleep.texi
@@ -19,6 +19,9 @@ nanosleep
 This function mishandles large arguments when interrupted by a signal on some
 platforms:
 Linux 64-bit, Solaris 64-bit.
address@hidden
+This function cannot sleep longer than 49.7 days on some platforms:
+Cygwin 1.5.x.
 @end itemize

 Portability problems not fixed by Gnulib:
diff --git a/doc/posix-functions/sleep.texi b/doc/posix-functions/sleep.texi
index 9a7a74f..6df8693 100644
--- a/doc/posix-functions/sleep.texi
+++ b/doc/posix-functions/sleep.texi
@@ -15,6 +15,9 @@ sleep
 This function takes milliseconds as argument and returns @code{void} on some
 platforms:
 mingw (2005 and older).
address@hidden
+This function cannot sleep longer than 49.7 days on some platforms:
+Cygwin 1.5.x.
 @end itemize

 Portability problems not fixed by Gnulib:
diff --git a/lib/sleep.c b/lib/sleep.c
index 9c56b9b..f706135 100644
--- a/lib/sleep.c
+++ b/lib/sleep.c
@@ -1,5 +1,5 @@
 /* Pausing execution of the current thread.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
    Written by Bruno Haible <address@hidden>, 2007.

    This program is free software: you can redistribute it and/or modify
@@ -39,7 +39,29 @@ sleep (unsigned int seconds)
   return remaining;
 }

-#else
+#elif HAVE_SLEEP
+
+# undef sleep
+
+/* Guarantee unlimited sleep and a reasonable return value.  Cygwin
+   1.5.x rejects attempts to sleep more than 49.7 days (2**32
+   milliseconds), but uses uninitialized memory which results in a
+   garbage answer.  */
+unsigned int
+rpl_sleep (unsigned int seconds)
+{
+  const unsigned int limit = 49 * 24 * 60 * 60;
+  while (limit < seconds)
+    {
+      seconds -= limit;
+      unsigned int result = sleep (limit);
+      if (result)
+        return seconds + result;
+    }
+  return sleep (seconds);
+}
+
+#else /* !HAVE_SLEEP */

  #error "Please port gnulib sleep.c to your platform, possibly using usleep() 
or select(), then report this to bug-gnulib."

diff --git a/lib/unistd.in.h b/lib/unistd.in.h
index 30f7bdd..9a9a671 100644
--- a/lib/unistd.in.h
+++ b/lib/unistd.in.h
@@ -714,11 +714,15 @@ extern int rmdir (char const *name);


 #if @GNULIB_SLEEP@
+# if @REPLACE_SLEEP@
+#  undef sleep
+#  define sleep rpl_sleep
+# endif
 /* Pause the execution of the current thread for N seconds.
    Returns the number of seconds left to sleep.
    See the POSIX:2001 specification
    <http://www.opengroup.org/susv3xsh/sleep.html>.  */
-# if address@hidden@
+# if address@hidden@ || @REPLACE_SLEEP@
 extern unsigned int sleep (unsigned int n);
 # endif
 #elif defined GNULIB_POSIXCHECK
diff --git a/m4/sleep.m4 b/m4/sleep.m4
index 474ba07..fb8c456 100644
--- a/m4/sleep.m4
+++ b/m4/sleep.m4
@@ -1,5 +1,5 @@
-# sleep.m4 serial 2
-dnl Copyright (C) 2007-2008 Free Software Foundation, Inc.
+# sleep.m4 serial 3
+dnl Copyright (C) 2007-2009 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
@@ -13,12 +13,37 @@ AC_DEFUN([gl_FUNC_SLEEP],
   dnl it takes the number of milliseconds as argument and returns void.
   dnl mingw does not declare this function.
   AC_CHECK_DECLS([sleep], , , [#include <unistd.h>])
+  AC_CHECK_FUNCS_ONCE([sleep])
   if test $ac_cv_have_decl_sleep != yes; then
     HAVE_SLEEP=0
     AC_LIBOBJ([sleep])
-    gl_PREREQ_SLEEP
+  else
+    dnl Cygwin 1.5.x has a bug where sleep can't exceed 49.7 days.
+    AC_CACHE_CHECK([for working sleep], [gl_cv_func_sleep_works],
+      [AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+static void
+handle_alarm (int sig)
+{
+  if (sig != SIGALRM)
+    _exit (2);
+}
+]], [[
+    /* Failure to compile this test due to missing alarm is okay,
+       since all such platforms (mingw) also lack sleep.  */
+    time_t pentecost = 50 * 24 * 60 * 60; /* 50 days.  */
+    time_t remaining;
+    signal (SIGALRM, handle_alarm);
+    alarm (1);
+    remaining = sleep (pentecost);
+    return !(pentecost - 10 < remaining && remaining <= pentecost);]])],
+      [gl_cv_func_sleep_works=yes], [gl_cv_func_sleep_works=no],
+      [gl_cv_func_sleep_works="guessing no"])])
+    if test "$gl_cv_func_sleep_works" != yes; then
+      REPLACE_SLEEP=1
+      AC_LIBOBJ([sleep])
+    fi
   fi
 ])
-
-# Prerequisites of lib/sleep.c.
-AC_DEFUN([gl_PREREQ_SLEEP], [:])
diff --git a/m4/unistd_h.m4 b/m4/unistd_h.m4
index 25bdb59..0a5b5d5 100644
--- a/m4/unistd_h.m4
+++ b/m4/unistd_h.m4
@@ -1,4 +1,4 @@
-# unistd_h.m4 serial 35
+# unistd_h.m4 serial 36
 dnl Copyright (C) 2006-2009 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -113,6 +113,7 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS],
   REPLACE_LSEEK=0;        AC_SUBST([REPLACE_LSEEK])
   REPLACE_READLINK=0;     AC_SUBST([REPLACE_READLINK])
   REPLACE_RMDIR=0;        AC_SUBST([REPLACE_RMDIR])
+  REPLACE_SLEEP=0;        AC_SUBST([REPLACE_SLEEP])
   REPLACE_SYMLINK=0;      AC_SUBST([REPLACE_SYMLINK])
   REPLACE_UNLINK=0;       AC_SUBST([REPLACE_UNLINK])
   REPLACE_UNLINKAT=0;     AC_SUBST([REPLACE_UNLINKAT])
diff --git a/modules/sleep-tests b/modules/sleep-tests
index 91de2ee..77f41fd 100644
--- a/modules/sleep-tests
+++ b/modules/sleep-tests
@@ -4,6 +4,7 @@ tests/test-sleep.c
 Depends-on:

 configure.ac:
+AC_CHECK_DECLS_ONCE([alarm])

 Makefile.am:
 TESTS += test-sleep
diff --git a/modules/unistd b/modules/unistd
index 008ccdf..1282e53 100644
--- a/modules/unistd
+++ b/modules/unistd
@@ -105,6 +105,7 @@ unistd.h: unistd.in.h
              -e 's|@''REPLACE_LSEEK''@|$(REPLACE_LSEEK)|g' \
              -e 's|@''REPLACE_READLINK''@|$(REPLACE_READLINK)|g' \
              -e 's|@''REPLACE_RMDIR''@|$(REPLACE_RMDIR)|g' \
+             -e 's|@''REPLACE_SLEEP''@|$(REPLACE_SLEEP)|g' \
              -e 's|@''REPLACE_SYMLINK''@|$(REPLACE_SYMLINK)|g' \
              -e 's|@''REPLACE_UNLINK''@|$(REPLACE_UNLINK)|g' \
              -e 's|@''REPLACE_UNLINKAT''@|$(REPLACE_UNLINKAT)|g' \
diff --git a/tests/test-sleep.c b/tests/test-sleep.c
index ed5a5a0..8c15371 100644
--- a/tests/test-sleep.c
+++ b/tests/test-sleep.c
@@ -1,5 +1,5 @@
 /* Test of sleep() function.
-   Copyright (C) 2007-2008 Free Software Foundation, Inc.
+   Copyright (C) 2007-2009 Free Software Foundation, Inc.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@

 #include <unistd.h>

+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>

@@ -35,6 +36,15 @@
     }                                                                       \
   while (0)

+#if HAVE_DECL_ALARM
+static void
+handle_alarm (int sig)
+{
+  if (sig != SIGALRM)
+    _exit (1);
+}
+#endif
+
 int
 main()
 {
@@ -42,6 +52,16 @@ main()

   ASSERT (sleep (0) == 0);

+#if HAVE_DECL_ALARM
+  {
+    const time_t pentecost = 50 * 24 * 60 * 60; /* 50 days.  */
+    time_t remaining;
+    signal (SIGALRM, handle_alarm);
+    alarm (1);
+    remaining = sleep (pentecost);
+    ASSERT (pentecost - 10 < remaining && remaining <= pentecost);
+  }
+#endif
+
   return 0;
 }
-
-- 
1.6.4.2








reply via email to

[Prev in Thread] Current Thread [Next in Thread]