+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
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:
/* 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
/* 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 */
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."
#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
-# 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.
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], [:])
-# 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,
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])
m4/sleep.m4
Depends-on:
+stdint
unistd
+verify
configure.ac:
gl_FUNC_SLEEP
Depends-on:
configure.ac:
+AC_CHECK_DECLS_ONCE([alarm])
Makefile.am:
TESTS += test-sleep
check_PROGRAMS += test-sleep
-
-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' \
/* 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
#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()
{
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;
}
-