]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
timeout: support sub-second timeouts on macOS
authorPádraig Brady <P@draigBrady.com>
Sat, 7 Nov 2020 21:35:01 +0000 (21:35 +0000)
committerPádraig Brady <P@draigBrady.com>
Sat, 7 Nov 2020 21:35:01 +0000 (21:35 +0000)
* m4/jm-macros.m4: Check for setitimer.
* src/timeout.c: Use setitimer if timer_settime is not available.
* NEWS: Mention the improvement.

NEWS
m4/jm-macros.m4
src/timeout.c

diff --git a/NEWS b/NEWS
index efb97e6b0a4d709a844fbce25585df2880ffb6c2..392d0ce1e2eb95e672d2efe44c72200903f7be05 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -44,6 +44,8 @@ GNU coreutils NEWS                                    -*- outline -*-
   file system types.  stat -f -c%T now reports the file system type,
   and tail -f uses polling for "vboxsf" and inotify for the others.
 
+  timeout now supports sub-second timeouts on macOS.
+
 
 * Noteworthy changes in release 8.32 (2020-03-05) [stable]
 
index 08efde3306666c1b466e51cdd0a2e6c863dd620f..2662351137da5c78201e2118655dc1b4d3ede779 100644 (file)
@@ -72,7 +72,7 @@ AC_DEFUN([coreutils_MACROS],
   # Used by sort.c.
   AC_CHECK_FUNCS_ONCE([nl_langinfo])
   # Used by timeout.c
-  AC_CHECK_FUNCS_ONCE([setrlimit prctl])
+  AC_CHECK_FUNCS_ONCE([setitimer setrlimit prctl])
 
   # Used by tail.c.
   AC_CHECK_FUNCS([inotify_init],
index 2b5d930e959d7ab6cea0acc1bf9aa43eb3242f6d..ca6ab87eb7794ac1716255bbdc8215cd5c89a9b3 100644 (file)
@@ -114,14 +114,9 @@ static void
 settimeout (double duration, bool warn)
 {
 
-/* timer_settime() provides potentially nanosecond resolution.
-   setitimer() is more portable (to Darwin for example),
-   but only provides microsecond resolution and thus is
-   a little more awkward to use with timespecs, as well as being
-   deprecated by POSIX.  Instead we fallback to single second
-   resolution provided by alarm().  */
-
 #if HAVE_TIMER_SETTIME
+  /* timer_settime() provides potentially nanosecond resolution.  */
+
   struct timespec ts = dtotimespec (duration);
   struct itimerspec its = { {0, 0}, ts };
   timer_t timerid;
@@ -138,8 +133,37 @@ settimeout (double duration, bool warn)
     }
   else if (warn && errno != ENOSYS)
     error (0, errno, _("warning: timer_create"));
+
+#elif HAVE_SETITIMER
+  /* setitimer() is more portable (to Darwin for example),
+     but only provides microsecond resolution.  */
+
+  struct timeval tv;
+  struct timespec ts = dtotimespec (duration);
+  tv.tv_sec = ts.tv_sec;
+  tv.tv_usec = (ts.tv_nsec + 999) / 1000;
+  if (tv.tv_usec == 1000 * 1000)
+    {
+      if (tv.tv_sec != TYPE_MAXIMUM (time_t))
+        {
+          tv.tv_sec++;
+          tv.tv_usec = 0;
+        }
+      else
+        tv.tv_usec--;
+    }
+  struct itimerval it = { {0, 0}, tv };
+  if (setitimer (ITIMER_REAL, &it, NULL) == 0)
+    return;
+  else
+    {
+      if (warn && errno != ENOSYS)
+        error (0, errno, _("warning: setitimer"));
+    }
 #endif
 
+  /* fallback to single second resolution provided by alarm().  */
+
   unsigned int timeint;
   if (UINT_MAX <= duration)
     timeint = UINT_MAX;