summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Blake <ebb9@byu.net>2009-11-18 20:07:44 -0700
committerEric Blake <ebb9@byu.net>2009-11-20 07:10:22 -0700
commit6baa46639c17d7fba1d6aa1a3dd8ed536b7b2dc9 (patch)
treeeac303353244b06ab50ddff551f46ec8d2230c26
parent00b2f10b68593189be4eb1affd88de33a8e92fb3 (diff)
downloadgnulib-6baa46639c17d7fba1d6aa1a3dd8ed536b7b2dc9.tar.gz
sleep: work around cygwin bug
On cygwin 1.5.x, sleep amounts larger than 49.7 days (2**32 milliseconds) failed instantly, but with a garbage return value from uninitialized memory. * lib/sleep.c (rpl_sleep): Work around the bug. * m4/sleep.m4 (gl_FUNC_SLEEP): Detect the bug. (gl_PREREQ_SLEEP): Delete unused macro. * modules/sleep (Depends-on): Add verify. * 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. * tests/test-sleep.c (main) [HAVE_DECL_ALARM]: Test it. * modules/sleep-tests (Depends-on): Check for alarm. Signed-off-by: Eric Blake <ebb9@byu.net>
-rw-r--r--ChangeLog14
-rw-r--r--doc/posix-functions/sleep.texi3
-rw-r--r--lib/sleep.c33
-rw-r--r--lib/unistd.in.h6
-rw-r--r--m4/sleep.m437
-rw-r--r--m4/unistd_h.m43
-rw-r--r--modules/sleep2
-rw-r--r--modules/sleep-tests2
-rw-r--r--modules/unistd1
-rw-r--r--tests/test-sleep.c40
10 files changed, 120 insertions, 21 deletions
diff --git a/ChangeLog b/ChangeLog
index 51fe8ed2c0..23aa5749e4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2009-11-20 Eric Blake <ebb9@byu.net>
+
+ sleep: work around cygwin bug
+ * lib/sleep.c (rpl_sleep): Work around the bug.
+ * m4/sleep.m4 (gl_FUNC_SLEEP): Detect the bug.
+ (gl_PREREQ_SLEEP): Delete unused macro.
+ * modules/sleep (Depends-on): Add verify.
+ * 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.
+ * tests/test-sleep.c (main) [HAVE_DECL_ALARM]: Test it.
+ * modules/sleep-tests (Depends-on): Check for alarm.
+
2009-11-20 Jim Meyering <meyering@redhat.com>
maint.mk: improve sc_prohibit_magic_number_exit
diff --git a/doc/posix-functions/sleep.texi b/doc/posix-functions/sleep.texi
index 9a7a74f0bd..6df8693842 100644
--- a/doc/posix-functions/sleep.texi
+++ b/doc/posix-functions/sleep.texi
@@ -15,6 +15,9 @@ mingw (2005 or newer).
This function takes milliseconds as argument and returns @code{void} on some
platforms:
mingw (2005 and older).
+@item
+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 9c56b9b81d..90b482c146 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 <bruno@clisp.org>, 2007.
This program is free software: you can redistribute it and/or modify
@@ -20,6 +20,10 @@
/* Specification. */
#include <unistd.h>
+#include <limits.h>
+
+#include "verify.h"
+
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
# define WIN32_LEAN_AND_MEAN /* avoid including junk */
@@ -39,7 +43,32 @@ 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)
+{
+ /* This requires int larger than 16 bits. */
+ verify (UINT_MAX / 49 / 24 / 60 / 60);
+ const unsigned int limit = 49 * 24 * 60 * 60;
+ while (limit < seconds)
+ {
+ unsigned int result;
+ seconds -= limit;
+ 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 30f7bddc27..9a9a671115 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 !@HAVE_SLEEP@
+# if !@HAVE_SLEEP@ || @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 474ba07ba9..c59b383bf3 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. */
+ unsigned int pentecost = 50 * 24 * 60 * 60; /* 50 days. */
+ unsigned int 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 25bdb59460..0a5b5d5a75 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 b/modules/sleep
index d8af51436a..e859e59e52 100644
--- a/modules/sleep
+++ b/modules/sleep
@@ -6,7 +6,9 @@ lib/sleep.c
m4/sleep.m4
Depends-on:
+stdint
unistd
+verify
configure.ac:
gl_FUNC_SLEEP
diff --git a/modules/sleep-tests b/modules/sleep-tests
index 91de2eeed1..0871d5117c 100644
--- a/modules/sleep-tests
+++ b/modules/sleep-tests
@@ -4,8 +4,8 @@ tests/test-sleep.c
Depends-on:
configure.ac:
+AC_CHECK_DECLS_ONCE([alarm])
Makefile.am:
TESTS += test-sleep
check_PROGRAMS += test-sleep
-
diff --git a/modules/unistd b/modules/unistd
index 008ccdf58d..1282e5380c 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 ed5a5a0c4a..48abce12f6 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,21 +20,31 @@
#include <unistd.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#define ASSERT(expr) \
- do \
- { \
- if (!(expr)) \
- { \
+ do \
+ { \
+ if (!(expr)) \
+ { \
fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
- fflush (stderr); \
- abort (); \
- } \
- } \
+ fflush (stderr); \
+ abort (); \
+ } \
+ } \
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 unsigned int pentecost = 50 * 24 * 60 * 60; /* 50 days. */
+ unsigned int remaining;
+ signal (SIGALRM, handle_alarm);
+ alarm (1);
+ remaining = sleep (pentecost);
+ ASSERT (pentecost - 10 < remaining && remaining <= pentecost);
+ }
+#endif
+
return 0;
}
-