# for nvlist_lookup_uint64_array
src_stat_LDADD += $(LIB_NVPAIR)
+# for fegetround, fesetround
+src_timeout_LDADD += $(FENV_ROUNDING_LIBM)
+
# for gettime, settime, tempname, utimecmp, utimens
copy_ldadd += $(CLOCK_TIME_LIB)
src_date_LDADD += $(CLOCK_TIME_LIB)
Written by Pádraig Brady. */
#include <config.h>
+#include <fenv.h>
#include <getopt.h>
+#include <math.h>
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include "system.h"
#include "cl-strtod.h"
-#include "xstrtod.h"
#include "sig2str.h"
#include "operand2sig.h"
#include "quote.h"
static double
parse_duration (char const *str)
{
- double duration;
- char const *ep;
+ /* If possible tell strtod to round up, so that we always wait at
+ least as long as STR specifies. Although Standard C requires
+ FENV_ACCESS ON, don't bother if using GCC as it warns. */
+#ifdef FE_UPWARD
+# if !defined __GNUC__ && 199901 <= __STDC_VERSION__
+# pragma STDC FENV_ACCESS ON
+# endif
+ int round = fegetround ();
+ fesetround (FE_UPWARD);
+#endif
+
+ char *ep;
+ double duration = cl_strtod (str, &ep);
+
+#ifdef FE_UPWARD
+ fesetround (round);
+#endif
- if (! (xstrtod (str, &ep, &duration, cl_strtod) || errno == ERANGE)
+ if (ep == str
/* Nonnegative interval. */
|| ! (0 <= duration)
+ /* The interval did not underflow to -0. */
+ || (signbit (duration) && errno == ERANGE)
/* No extra chars after the number and an optional s,m,h,d char. */
|| (*ep && *(ep + 1))
/* Check any suffix char and update timeout based on the suffix. */
usage (EXIT_CANCELED);
}
- /* Clamp underflow to 1ns, as 0 disables the timeout. */
+ /* Do not let the duration underflow to 0, as 0 disables the timeout.
+ Use 2**-30 instead of 0; settimeout will round it up to 1 ns,
+ whereas 1e-9 might double-round to 2 ns.
+
+ If FE_UPWARD is defined, this code is not needed on glibc as its
+ strtod rounds upward correctly. Although this code might not be
+ needed on non-glibc platforms too, it's too much trouble to
+ worry about that. */
+#if !defined FE_UPWARD || !defined __GLIBC__
if (duration == 0 && errno == ERANGE)
- duration = 1e-9;
+ duration = 9.313225746154785e-10;
+#endif
return duration;
}
# internal errors are 125, distinct from execution failure
-# invalid timeout
+# invalid timeouts
returns_ 125 timeout invalid sleep 0 || fail=1
+returns_ 125 timeout ' -0.1' sleep 0 || fail=1
+returns_ 125 timeout ' -1e-10000' sleep 0 || fail=1
# invalid kill delay
returns_ 125 timeout --kill-after=invalid 1 sleep 0 || fail=1
# nanoseconds potentially supported
timeout 9.999999999 sleep 0 || fail=1
+# round underflow up to 1 ns
+returns_ 124 timeout 1e-10000 sleep 1 || fail
+
# invalid signal spec
returns_ 125 timeout --signal=invalid 1 sleep 0 || fail=1