Mercurial > gnulib
changeset 39833:4c9d0c898076
timespec: fix resolution confusion
In normal usage, clock resolution is given in seconds, but the
code was mistakenly using inverse seconds and calling it
“resolution”. Fix this, partly by renaming two identifiers.
The old names will be kept for a bit, to ease transition.
* lib/timespec.h (TIMESPEC_HZ, LOG10_TIMESPEC_HZ):
New constants, replacing TIMESPEC_RESOLUTION and
LOG10_TIMESPEC_RESOLUTION, which are now obsolescent.
All uses changed.
author | Paul Eggert <eggert@cs.ucla.edu> |
---|---|
date | Mon, 10 Sep 2018 18:42:25 -0700 |
parents | 8228a72f9f50 |
children | d5a1b82291f0 |
files | ChangeLog doc/posix-functions/futimens.texi doc/posix-functions/utimensat.texi lib/dtotimespec.c lib/stat-time.h lib/timespec-add.c lib/timespec-sub.c lib/timespec.h lib/utimens.c lib/utimensat.c tests/test-futimens.h tests/test-timespec.c tests/test-utimens.h |
diffstat | 13 files changed, 62 insertions(+), 44 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Sun Sep 09 08:56:15 2018 -0700 +++ b/ChangeLog Mon Sep 10 18:42:25 2018 -0700 @@ -1,3 +1,15 @@ +2018-09-10 Paul Eggert <eggert@cs.ucla.edu> + + timespec: fix resolution confusion + In normal usage, clock resolution is given in seconds, but the + code was mistakenly using inverse seconds and calling it + “resolution”. Fix this, partly by renaming two identifiers. + The old names will be kept for a bit, to ease transition. + * lib/timespec.h (TIMESPEC_HZ, LOG10_TIMESPEC_HZ): + New constants, replacing TIMESPEC_RESOLUTION and + LOG10_TIMESPEC_RESOLUTION, which are now obsolescent. + All uses changed. + 2018-09-09 Paul Eggert <eggert@cs.ucla.edu> mktime: simplify in prep for glibc merge
--- a/doc/posix-functions/futimens.texi Sun Sep 09 08:56:15 2018 -0700 +++ b/doc/posix-functions/futimens.texi Mon Sep 10 18:42:25 2018 -0700 @@ -12,7 +12,7 @@ This function is missing on some platforms: glibc 2.3.6, Mac OS X 10.5, FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin 1.5.x, mingw, MSVC 14, Interix 3.5, BeOS, Android 4.3. However, the replacement function may end up truncating timestamps to -less resolution than supported by the file system. +worse resolution than supported by the file system. @item This function returns a bogus value instead of failing with @code{ENOSYS} on some platforms:
--- a/doc/posix-functions/utimensat.texi Sun Sep 09 08:56:15 2018 -0700 +++ b/doc/posix-functions/utimensat.texi Mon Sep 10 18:42:25 2018 -0700 @@ -12,7 +12,7 @@ This function is missing on some platforms: glibc 2.3.6, Mac OS X 10.5, FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin 1.5.x, mingw, MSVC 14, Interix 3.5, BeOS, Android 3.0. However, the replacement function may end up truncating timestamps to -less resolution than supported by the file system. Furthermore, the +worse resolution than supported by the file system. Furthermore, the replacement function is not safe to be used in libraries and is not multithread-safe. @item
--- a/lib/dtotimespec.c Sun Sep 09 08:56:15 2018 -0700 +++ b/lib/dtotimespec.c Mon Sep 10 18:42:25 2018 -0700 @@ -32,20 +32,20 @@ if (! (TYPE_MINIMUM (time_t) < sec)) return make_timespec (TYPE_MINIMUM (time_t), 0); else if (! (sec < 1.0 + TYPE_MAXIMUM (time_t))) - return make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_RESOLUTION - 1); + return make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_HZ - 1); else { time_t s = sec; - double frac = TIMESPEC_RESOLUTION * (sec - s); + double frac = TIMESPEC_HZ * (sec - s); long ns = frac; ns += ns < frac; - s += ns / TIMESPEC_RESOLUTION; - ns %= TIMESPEC_RESOLUTION; + s += ns / TIMESPEC_HZ; + ns %= TIMESPEC_HZ; if (ns < 0) { s--; - ns += TIMESPEC_RESOLUTION; + ns += TIMESPEC_HZ; } return make_timespec (s, ns);
--- a/lib/stat-time.h Sun Sep 09 08:56:15 2018 -0700 +++ b/lib/stat-time.h Mon Sep 10 18:42:25 2018 -0700 @@ -213,7 +213,7 @@ #if defined __sun && defined STAT_TIMESPEC if (result == 0) { - long int timespec_resolution = 1000000000; + long int timespec_hz = 1000000000; short int const ts_off[] = { offsetof (struct stat, st_atim), offsetof (struct stat, st_mtim), offsetof (struct stat, st_ctim) }; @@ -221,11 +221,11 @@ for (i = 0; i < sizeof ts_off / sizeof *ts_off; i++) { struct timespec *ts = (struct timespec *) ((char *) st + ts_off[i]); - long int q = ts->tv_nsec / timespec_resolution; - long int r = ts->tv_nsec % timespec_resolution; + long int q = ts->tv_nsec / timespec_hz; + long int r = ts->tv_nsec % timespec_hz; if (r < 0) { - r += timespec_resolution; + r += timespec_hz; q--; } ts->tv_nsec = r;
--- a/lib/timespec-add.c Sun Sep 09 08:56:15 2018 -0700 +++ b/lib/timespec-add.c Mon Sep 10 18:42:25 2018 -0700 @@ -18,7 +18,7 @@ /* Written by Paul Eggert. */ /* Return the sum of two timespec values A and B. On overflow, return - an extremal value. This assumes 0 <= tv_nsec < TIMESPEC_RESOLUTION. */ + an extremal value. This assumes 0 <= tv_nsec < TIMESPEC_HZ. */ #include <config.h> #include "timespec.h" @@ -31,7 +31,7 @@ time_t rs = a.tv_sec; time_t bs = b.tv_sec; int ns = a.tv_nsec + b.tv_nsec; - int nsd = ns - TIMESPEC_RESOLUTION; + int nsd = ns - TIMESPEC_HZ; int rns = ns; time_t tmin = TYPE_MINIMUM (time_t); time_t tmax = TYPE_MAXIMUM (time_t); @@ -63,7 +63,7 @@ { high_overflow: rs = tmax; - rns = TIMESPEC_RESOLUTION - 1; + rns = TIMESPEC_HZ - 1; } }
--- a/lib/timespec-sub.c Sun Sep 09 08:56:15 2018 -0700 +++ b/lib/timespec-sub.c Mon Sep 10 18:42:25 2018 -0700 @@ -19,7 +19,7 @@ /* Return the difference between two timespec values A and B. On overflow, return an extremal value. This assumes 0 <= tv_nsec < - TIMESPEC_RESOLUTION. */ + TIMESPEC_HZ. */ #include <config.h> #include "timespec.h" @@ -38,7 +38,7 @@ if (ns < 0) { - rns = ns + TIMESPEC_RESOLUTION; + rns = ns + TIMESPEC_HZ; if (bs < tmax) bs++; else if (- TYPE_SIGNED (time_t) < rs) @@ -63,7 +63,7 @@ else { rs = tmax; - rns = TIMESPEC_RESOLUTION - 1; + rns = TIMESPEC_HZ - 1; } }
--- a/lib/timespec.h Sun Sep 09 08:56:15 2018 -0700 +++ b/lib/timespec.h Mon Sep 10 18:42:25 2018 -0700 @@ -35,11 +35,17 @@ #include "verify.h" -/* Resolution of timespec timestamps (in units per second), and log - base 10 of the resolution. */ +/* Inverse resolution of timespec timestamps (in units per second), + and log base 10 of the inverse resolution. */ + +enum { TIMESPEC_HZ = 1000000000 }; +enum { LOG10_TIMESPEC_HZ = 9 }; -enum { TIMESPEC_RESOLUTION = 1000000000 }; -enum { LOG10_TIMESPEC_RESOLUTION = 9 }; +/* Obsolescent names for backward compatibility. + They are misnomers, because TIMESPEC_RESOLUTION is not a resolution. */ + +enum { TIMESPEC_RESOLUTION = TIMESPEC_HZ }; +enum { LOG10_TIMESPEC_RESOLUTION = LOG10_TIMESPEC_HZ }; /* Return a timespec with seconds S and nanoseconds NS. */ @@ -88,8 +94,8 @@ /* Pacify gcc -Wstrict-overflow (bleeding-edge circa 2017-10-02). See: https://lists.gnu.org/r/bug-gnulib/2017-10/msg00006.html */ - assume (-1 <= a.tv_nsec && a.tv_nsec <= 2 * TIMESPEC_RESOLUTION); - assume (-1 <= b.tv_nsec && b.tv_nsec <= 2 * TIMESPEC_RESOLUTION); + assume (-1 <= a.tv_nsec && a.tv_nsec <= 2 * TIMESPEC_HZ); + assume (-1 <= b.tv_nsec && b.tv_nsec <= 2 * TIMESPEC_HZ); return a.tv_nsec - b.tv_nsec; }
--- a/lib/utimens.c Sun Sep 09 08:56:15 2018 -0700 +++ b/lib/utimens.c Mon Sep 10 18:42:25 2018 -0700 @@ -91,11 +91,11 @@ if ((timespec[0].tv_nsec != UTIME_NOW && timespec[0].tv_nsec != UTIME_OMIT && ! (0 <= timespec[0].tv_nsec - && timespec[0].tv_nsec < TIMESPEC_RESOLUTION)) + && timespec[0].tv_nsec < TIMESPEC_HZ)) || (timespec[1].tv_nsec != UTIME_NOW && timespec[1].tv_nsec != UTIME_OMIT && ! (0 <= timespec[1].tv_nsec - && timespec[1].tv_nsec < TIMESPEC_RESOLUTION))) + && timespec[1].tv_nsec < TIMESPEC_HZ))) { errno = EINVAL; return -1;
--- a/lib/utimensat.c Sun Sep 09 08:56:15 2018 -0700 +++ b/lib/utimensat.c Mon Sep 10 18:42:25 2018 -0700 @@ -94,10 +94,10 @@ else if (times && ((times[0].tv_nsec != UTIME_NOW && ! (0 <= times[0].tv_nsec - && times[0].tv_nsec < TIMESPEC_RESOLUTION)) + && times[0].tv_nsec < TIMESPEC_HZ)) || (times[1].tv_nsec != UTIME_NOW && ! (0 <= times[1].tv_nsec - && times[1].tv_nsec < TIMESPEC_RESOLUTION)))) + && times[1].tv_nsec < TIMESPEC_HZ)))) { errno = EINVAL; return -1;
--- a/tests/test-futimens.h Sun Sep 09 08:56:15 2018 -0700 +++ b/tests/test-futimens.h Mon Sep 10 18:42:25 2018 -0700 @@ -47,7 +47,7 @@ } ASSERT (!result); ASSERT (fstat (fd, &st2) == 0); - /* If utimens truncates to less resolution than the file system + /* If utimens truncates to worse resolution than the file system supports, then time can appear to go backwards between now and a follow-up utimens with UTIME_NOW or a NULL timespec. Use UTIMECMP_TRUNCATE_SOURCE to compensate, with st1 as the
--- a/tests/test-timespec.c Sun Sep 09 08:56:15 2018 -0700 +++ b/tests/test-timespec.c Mon Sep 10 18:42:25 2018 -0700 @@ -30,36 +30,36 @@ { { INT_MIN, 0 }, { INT_MIN, 1 }, - { INT_MIN, TIMESPEC_RESOLUTION - 1 }, + { INT_MIN, TIMESPEC_HZ - 1 }, { INT_MIN + 1, 0 }, { INT_MIN + 1, 1 }, - { INT_MIN + 1, TIMESPEC_RESOLUTION - 1 }, + { INT_MIN + 1, TIMESPEC_HZ - 1 }, { -1, 0 }, { -1, 1 }, - { -1, TIMESPEC_RESOLUTION - 1 }, + { -1, TIMESPEC_HZ - 1 }, { 0, 0 }, { 0, 1 }, - { 0, TIMESPEC_RESOLUTION - 1 }, + { 0, TIMESPEC_HZ - 1 }, { 1, 0 }, { 1, 1 }, - { 1, TIMESPEC_RESOLUTION - 1 }, + { 1, TIMESPEC_HZ - 1 }, { 1234567890, 0 }, { 1234567890, 1 }, - { 1234567890, TIMESPEC_RESOLUTION - 1 }, + { 1234567890, TIMESPEC_HZ - 1 }, { INT_MAX - 1, 0 }, { INT_MAX - 1, 1 }, - { INT_MAX - 1, TIMESPEC_RESOLUTION - 1 }, + { INT_MAX - 1, TIMESPEC_HZ - 1 }, { INT_MAX, 0 }, { INT_MAX, 1 }, - { INT_MAX, TIMESPEC_RESOLUTION - 1 }, - { INT_MAX, 2 * TIMESPEC_RESOLUTION } + { INT_MAX, TIMESPEC_HZ - 1 }, + { INT_MAX, 2 * TIMESPEC_HZ } }; enum { nprototypes = sizeof prototype / sizeof *prototype }; static bool valid (struct timespec a) { - return 0 <= a.tv_nsec && a.tv_nsec < TIMESPEC_RESOLUTION; + return 0 <= a.tv_nsec && a.tv_nsec < TIMESPEC_HZ; } static int @@ -85,7 +85,7 @@ { return ((a.tv_sec == TYPE_MINIMUM (time_t) && a.tv_nsec == 0) || (a.tv_sec == TYPE_MAXIMUM (time_t) - && a.tv_nsec == TIMESPEC_RESOLUTION - 1)); + && a.tv_nsec == TIMESPEC_HZ - 1)); } int @@ -94,7 +94,7 @@ int i, j, k; struct timespec test[nprototypes + 1]; int ntests; - int computed_resolution = 1; + int computed_hz = 1; struct timespec prevroundtrip; test[0] = make_timespec (TYPE_MINIMUM (time_t), -1); @@ -111,9 +111,9 @@ } } - for (i = 0; i < LOG10_TIMESPEC_RESOLUTION; i++) - computed_resolution *= 10; - ASSERT (computed_resolution == TIMESPEC_RESOLUTION); + for (i = 0; i < LOG10_TIMESPEC_HZ; i++) + computed_hz *= 10; + ASSERT (computed_hz == TIMESPEC_HZ); for (i = 0; i < ntests; i++) {
--- a/tests/test-utimens.h Sun Sep 09 08:56:15 2018 -0700 +++ b/tests/test-utimens.h Mon Sep 10 18:42:25 2018 -0700 @@ -27,7 +27,7 @@ struct stat st2; ASSERT (close (creat (BASE "file", 0600)) == 0); - /* If utimens truncates to less resolution than the file system + /* If utimens truncates to worse resolution than the file system supports, then time can appear to go backwards between now and a follow-up utimens with UTIME_NOW or a NULL timespec. Use UTIMECMP_TRUNCATE_SOURCE to compensate, with st1 as the