usleep: new module
authorEric Blake <ebb9@byu.net>
Tue, 17 Nov 2009 16:24:56 +0000 (09:24 -0700)
committerEric Blake <ebb9@byu.net>
Wed, 18 Nov 2009 05:31:58 +0000 (22:31 -0700)
mingw usleep(1000000) failed with EINVAL, as allowed by POSIX,
but contrary to GNU usage.  Rather than implement an accurate
usleep based on select or nanosleep, both of which drag in
dependencies on external libraries, this version intentionally
takes the ceiling in seconds if usleep() is missing.

* modules/usleep: New file.
* m4/usleep.m4 (gl_FUNC_USLEEP): Likewise.
* lib/usleep.c (usleep): Likewise.
* m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Add defaults.
* modules/unistd (Makefile.am): Substitute witnesses.
* lib/unistd.in.h (usleep): Add declaration.
* doc/pastposix-functions/usleep.texi (usleep): Document this.
* MODULES.html.sh (Date and time): Likewise.
* modules/usleep-tests (Depends-on): New test.
* tests/test-usleep.c: New file.

Signed-off-by: Eric Blake <ebb9@byu.net>
ChangeLog
MODULES.html.sh
doc/pastposix-functions/usleep.texi
lib/unistd.in.h
lib/usleep.c [new file with mode: 0644]
m4/unistd_h.m4
m4/usleep.m4 [new file with mode: 0644]
modules/unistd
modules/usleep [new file with mode: 0644]
modules/usleep-tests [new file with mode: 0644]
tests/test-usleep.c [new file with mode: 0644]

index 599a94413fa6e8e068301dcb4add0e8d53d3709d..cf14b4ba159e63f2de5bf754c10974f94349b399 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
 2009-11-17  Eric Blake  <ebb9@byu.net>
 
+       usleep: new module
+       * modules/usleep: New file.
+       * m4/usleep.m4 (gl_FUNC_USLEEP): Likewise.
+       * lib/usleep.c (usleep): Likewise.
+       * m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Add defaults.
+       * modules/unistd (Makefile.am): Substitute witnesses.
+       * lib/unistd.in.h (usleep): Add declaration.
+       * doc/pastposix-functions/usleep.texi (usleep): Document this.
+       * MODULES.html.sh (Date and time): Likewise.
+       * modules/usleep-tests (Depends-on): New test.
+       * tests/test-usleep.c: New file.
+
        chown: work around OpenBSD bug
        * lib/chown.c (rpl_chown): Work around the bug.
        * lib/lchown.c (rpl_lchown): Attempt to do likewise.
index 7d42b736db5e7f59198743b76817f65d3928b23f..cb791b8e4d43bd44cb6ea55a89f60985662bb79f 100755 (executable)
@@ -2593,8 +2593,9 @@ func_all_modules ()
   func_begin_table
   func_module gethrxtime
   func_module gettime
-  func_module settime
   func_module posixtm
+  func_module settime
+  func_module usleep
   func_module xnanosleep
   func_end_table
 
index bb381520a6d25eede36c4d1cc889326e28553088..8ca0da9e5179334089d4de420efc0167e7df5bc1 100644 (file)
@@ -4,23 +4,25 @@
 
 POSIX specification: @url{http://www.opengroup.org/susv3xsh/usleep.html}
 
-Gnulib module: ---
+Gnulib module: usleep
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+On some systems, @code{usleep} rejects attempts to sleep longer than 1
+second, as allowed by POSIX:
+mingw.
+@item
+This function is missing on some platforms.  However, the replacement
+is designed to be lightweight, and may round to the neareset second;
+use @code{select} or @code{nanosleep} if better resolution is needed:
+IRIX 5.3, Solaris 2.4, older mingw, BeOS.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-This function is missing on some platforms:
-IRIX 5.3, Solaris 2.4, older mingw, BeOS.
-@item
 According to POSIX, the @code{usleep} function may interfere with the program's
 use of the @code{SIGALRM} signal.  On Linux, it doesn't; on other platforms,
 it may.
-@item
-On some systems, @code{usleep} rejects attempts to sleep longer than 1
-second, as allowed by POSIX:
-mingw.
 @end itemize
index c026b717840f8b0360c9fef55f33dcd052516a86..30f7bddc27c8c652dc00d589c813b5f98390685d 100644 (file)
@@ -792,6 +792,27 @@ extern int unlinkat (int fd, char const *file, int flag);
 #endif
 
 
+#if @GNULIB_USLEEP@
+# if @REPLACE_USLEEP@
+#  undef usleep
+#  define usleep rpl_usleep
+# endif
+# if !@HAVE_USLEEP@ || @REPLACE_USLEEP@
+/* Pause the execution of the current thread for N microseconds.
+   Returns 0 on completion, or -1 on range error.
+   See the POSIX:2001 specification
+   <http://www.opengroup.org/susv3xsh/sleep.html>.  */
+extern int usleep (useconds_t n);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef usleep
+# define usleep(n) \
+    (GL_LINK_WARNING ("usleep is unportable - " \
+                      "use gnulib module usleep for portability"), \
+     usleep (n))
+#endif
+
+
 #if @GNULIB_WRITE@ && @REPLACE_WRITE@ && @GNULIB_UNISTD_H_SIGPIPE@
 /* Write up to COUNT bytes starting at BUF to file descriptor FD.
    See the POSIX:2001 specification
diff --git a/lib/usleep.c b/lib/usleep.c
new file mode 100644 (file)
index 0000000..86f1fef
--- /dev/null
@@ -0,0 +1,58 @@
+/* Pausing execution of the current thread.
+   Copyright (C) 2009 Free Software Foundation, Inc.
+   Written by Eric Blake <ebb9@byu.net>, 2009.
+
+   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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* This file is _intentionally_ light-weight.  Rather than using
+   select or nanosleep, both of which drag in external libraries on
+   some platforms, this merely rounds up to the nearest second if
+   usleep() does not exist.  If sub-second resolution is important,
+   then use a more powerful interface to begin with.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#include <errno.h>
+
+#ifndef HAVE_USLEEP
+# define HAVE_USLEEP 0
+#endif
+
+/* Sleep for MICRO microseconds, which can be greater than 1 second.
+   Return -1 and set errno to EINVAL on range error (about 4295
+   seconds), or 0 on success.  Interaction with SIGALARM is
+   unspecified.  */
+
+int
+usleep (useconds_t micro)
+{
+  unsigned int seconds = micro / 1000000;
+  if (sizeof seconds < sizeof micro && micro / 1000000 != seconds)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+  if (!HAVE_USLEEP && micro % 1000000)
+    seconds++;
+  while ((seconds = sleep (seconds)) != 0);
+
+#undef usleep
+#if !HAVE_USLEEP
+# define usleep(x) 0
+#endif
+  return usleep (micro % 1000000);
+}
index 88e60a05383599868a1efc4b54b078db4925cfeb..25bdb594600870152e532240b7e4005f7f6012d2 100644 (file)
@@ -1,4 +1,4 @@
-# unistd_h.m4 serial 34
+# unistd_h.m4 serial 35
 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,
@@ -66,6 +66,7 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS],
   GNULIB_UNISTD_H_SIGPIPE=0; AC_SUBST([GNULIB_UNISTD_H_SIGPIPE])
   GNULIB_UNLINK=0;           AC_SUBST([GNULIB_UNLINK])
   GNULIB_UNLINKAT=0;         AC_SUBST([GNULIB_UNLINKAT])
+  GNULIB_USLEEP=0;           AC_SUBST([GNULIB_USLEEP])
   GNULIB_WRITE=0;            AC_SUBST([GNULIB_WRITE])
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_CHOWN=1;           AC_SUBST([HAVE_CHOWN])
@@ -96,6 +97,7 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS],
   HAVE_OS_H=0;            AC_SUBST([HAVE_OS_H])
   HAVE_SYS_PARAM_H=0;     AC_SUBST([HAVE_SYS_PARAM_H])
   HAVE_UNLINKAT=1;        AC_SUBST([HAVE_UNLINKAT])
+  HAVE_USLEEP=1;          AC_SUBST([HAVE_USLEEP])
   REPLACE_CHOWN=0;        AC_SUBST([REPLACE_CHOWN])
   REPLACE_CLOSE=0;        AC_SUBST([REPLACE_CLOSE])
   REPLACE_DUP=0;          AC_SUBST([REPLACE_DUP])
@@ -114,6 +116,7 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS],
   REPLACE_SYMLINK=0;      AC_SUBST([REPLACE_SYMLINK])
   REPLACE_UNLINK=0;       AC_SUBST([REPLACE_UNLINK])
   REPLACE_UNLINKAT=0;     AC_SUBST([REPLACE_UNLINKAT])
+  REPLACE_USLEEP=0;       AC_SUBST([REPLACE_USLEEP])
   REPLACE_WRITE=0;        AC_SUBST([REPLACE_WRITE])
   UNISTD_H_HAVE_WINSOCK2_H=0; AC_SUBST([UNISTD_H_HAVE_WINSOCK2_H])
   UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS=0;
diff --git a/m4/usleep.m4 b/m4/usleep.m4
new file mode 100644 (file)
index 0000000..c8e6911
--- /dev/null
@@ -0,0 +1,37 @@
+# usleep.m4 serial 1
+dnl Copyright (C) 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 This macro intentionally does not check for select or nanosleep;
+dnl both of those modules can require external libraries.
+AC_DEFUN([gl_FUNC_USLEEP],
+[
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+  dnl usleep was required in POSIX 2001, but dropped as obsolete in
+  dnl POSIX 2008; therefore, it is not always exposed in headers.
+  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+  AC_CHECK_FUNCS_ONCE([usleep])
+  AC_CHECK_TYPE([useconds_t], [],
+    [AC_DEFINE([useconds_t], [unsigned int], [Define to an unsigned 32-bit
+      type if <sys/types.h> lacks this type.])])
+  if test $ac_cv_func_usleep = no; then
+    HAVE_USLEEP=0
+    AC_LIBOBJ([usleep])
+  else
+    dnl POSIX allows implementations to reject arguments larger than
+    dnl 999999, but GNU guarantees it will work.
+    AC_CACHE_CHECK([whether usleep allows large arguments],
+      [gl_cv_func_usleep_works],
+      [AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <unistd.h>
+]], [[return !!usleep (1000000);]])],
+        [gl_cv_func_usleep_works=yes], [gl_cv_func_usleep_works=no],
+        [gl_cv_func_usleep_works="guessing no"])])
+    if test "$gl_cv_func_usleep_works" != yes; then
+      REPLACE_USLEEP=1
+      AC_LIBOBJ([usleep])
+    fi
+  fi
+])
index 1cb3b0b629110c4e134f8bd55f2fc1c2707fd6c7..008ccdf58d969ed610daa8960c33500cfbe3db24 100644 (file)
@@ -59,6 +59,7 @@ unistd.h: unistd.in.h
              -e 's|@''GNULIB_UNISTD_H_SIGPIPE''@|$(GNULIB_UNISTD_H_SIGPIPE)|g' \
              -e 's|@''GNULIB_UNLINK''@|$(GNULIB_UNLINK)|g' \
              -e 's|@''GNULIB_UNLINKAT''@|$(GNULIB_UNLINKAT)|g' \
+             -e 's|@''GNULIB_USLEEP''@|$(GNULIB_USLEEP)|g' \
              -e 's|@''GNULIB_WRITE''@|$(GNULIB_WRITE)|g' \
              -e 's|@''HAVE_CHOWN''@|$(HAVE_CHOWN)|g' \
              -e 's|@''HAVE_DUP2''@|$(HAVE_DUP2)|g' \
@@ -84,6 +85,7 @@ unistd.h: unistd.in.h
              -e 's|@''HAVE_SYMLINK''@|$(HAVE_SYMLINK)|g' \
              -e 's|@''HAVE_SYMLINKAT''@|$(HAVE_SYMLINKAT)|g' \
              -e 's|@''HAVE_UNLINKAT''@|$(HAVE_UNLINKAT)|g' \
+             -e 's|@''HAVE_USLEEP''@|$(HAVE_USLEEP)|g' \
              -e 's|@''HAVE_DECL_ENVIRON''@|$(HAVE_DECL_ENVIRON)|g' \
              -e 's|@''HAVE_DECL_GETLOGIN_R''@|$(HAVE_DECL_GETLOGIN_R)|g' \
              -e 's|@''HAVE_OS_H''@|$(HAVE_OS_H)|g' \
@@ -106,6 +108,7 @@ unistd.h: unistd.in.h
              -e 's|@''REPLACE_SYMLINK''@|$(REPLACE_SYMLINK)|g' \
              -e 's|@''REPLACE_UNLINK''@|$(REPLACE_UNLINK)|g' \
              -e 's|@''REPLACE_UNLINKAT''@|$(REPLACE_UNLINKAT)|g' \
+             -e 's|@''REPLACE_USLEEP''@|$(REPLACE_USLEEP)|g' \
              -e 's|@''REPLACE_WRITE''@|$(REPLACE_WRITE)|g' \
              -e 's|@''UNISTD_H_HAVE_WINSOCK2_H''@|$(UNISTD_H_HAVE_WINSOCK2_H)|g' \
              -e 's|@''UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS''@|$(UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS)|g' \
diff --git a/modules/usleep b/modules/usleep
new file mode 100644 (file)
index 0000000..c77826b
--- /dev/null
@@ -0,0 +1,26 @@
+Description:
+usleep() function: pause execution of the current thread.
+
+Files:
+lib/usleep.c
+m4/usleep.m4
+
+Depends-on:
+extensions
+sleep
+unistd
+
+configure.ac:
+gl_FUNC_USLEEP
+gl_UNISTD_MODULE_INDICATOR([usleep])
+
+Makefile.am:
+
+Include:
+<unistd.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+Eric Blake
diff --git a/modules/usleep-tests b/modules/usleep-tests
new file mode 100644 (file)
index 0000000..762d644
--- /dev/null
@@ -0,0 +1,11 @@
+Files:
+tests/test-usleep.c
+
+Depends-on:
+time
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-usleep
+check_PROGRAMS += test-usleep
diff --git a/tests/test-usleep.c b/tests/test-usleep.c
new file mode 100644 (file)
index 0000000..d6e62eb
--- /dev/null
@@ -0,0 +1,49 @@
+/* Test of usleep() function.
+   Copyright (C) 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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Eric Blake <ebb9@byu.net>, 2009.  */
+
+#include <config.h>
+
+#include <unistd.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#define ASSERT(expr) \
+  do                                                                         \
+    {                                                                        \
+      if (!(expr))                                                           \
+        {                                                                    \
+          fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
+          fflush (stderr);                                                   \
+          abort ();                                                          \
+        }                                                                    \
+    }                                                                        \
+  while (0)
+
+int
+main(void)
+{
+  time_t start = time (NULL);
+  ASSERT (usleep (1000000) == 0);
+  ASSERT (start < time (NULL));
+
+  ASSERT (usleep (0) == 0);
+
+  return 0;
+}