about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2019-09-03 18:07:28 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2019-09-03 18:07:28 +0000
commite69717d9e0cd107f461abff85f255be82d7bd69b (patch)
treea1158470fe0ea9afea4fb95e974464ac61fe058e
parent2aa26bce30a3a1d46979a011d85928dda927932c (diff)
downloadskalibs-e69717d9e0cd107f461abff85f255be82d7bd69b.tar.gz
skalibs-e69717d9e0cd107f461abff85f255be82d7bd69b.tar.xz
skalibs-e69717d9e0cd107f461abff85f255be82d7bd69b.zip
Big wallclock/stopwatch refactor. It was long overdue.
 * --enable-clock and --enable-monotonic are gone
 * tain_sysclock() has been renamed tain_wallclock_read()
 * tain_wallclock_read() reads from CLOCK_REALTIME (or gettimeofday())
 * tain_clockmon[_init]() have been renamed to tain_stopwatch_[read|init]()
and now accept a monotonic clock name as an extra argument
 * tain_now() points to the system (wall) clock by default
 * tain_now_set_[stopwatch|wallclock]() can be used to switch

 Now to make a pass on all skarnet.org programs and add a
tain_now_set_stopwatch() call everywhere needed... >.>
-rw-r--r--AUTHORS2
-rw-r--r--NEWS5
-rwxr-xr-xconfigure37
-rw-r--r--doc/flags.html30
-rw-r--r--doc/libstddjb/tai.html124
-rw-r--r--doc/upgrade.html6
-rw-r--r--package/deps.mak12
-rw-r--r--src/include/skalibs/tai.h23
-rw-r--r--src/libstddjb/sysclock_get.c10
-rw-r--r--src/libstddjb/sysclock_set.c14
-rw-r--r--src/libstddjb/tain_clockmon.c47
-rw-r--r--src/libstddjb/tain_now.c44
-rw-r--r--src/libstddjb/tain_now_set_stopwatch.c36
-rw-r--r--src/libstddjb/tain_now_set_wallclock.c10
-rw-r--r--src/libstddjb/tain_stopwatch.c50
-rw-r--r--src/libstddjb/tain_wallclock_read.c (renamed from src/libstddjb/tain_sysclock.c)2
-rw-r--r--src/libstddjb/timestamp_r.c2
-rw-r--r--src/sysdeps/tryclockboot.c10
18 files changed, 215 insertions, 249 deletions
diff --git a/AUTHORS b/AUTHORS
index cc2b7ee..d89bd8f 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -34,3 +34,5 @@ Thanks to:
   Samuel Holland <samuel@sholland.org>
   Jan Bramkamp <crest_maintainer@rlwinm.de>
   Johannes Nixdorf <mixi@shadowice.org>
+  Casper Ti. Vector <caspervector@gmail.com>
+  Guillermo <gdiazhartusch@gmail.com>
diff --git a/NEWS b/NEWS
index 6d05a58..8aa085e 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,11 @@ In 2.9.0.0
 that means better autotools emulation).
  - Build more friendly to recent glibc.
  - Refactoring and optimization of scanning and formatting functions.
+ - Refactoring of stopwatch/wallclock functions. The --enable-clock
+and --enable-monotonic configure switches have been removed.
+tain_now() can now be set at run time to use a wall clock (default,
+or via tain_now_set_wallclock()) or a stopwatch (via
+tain_now_set_stopwatch()), instead of it being fixed at build time.
 
 
 In 2.8.1.0
diff --git a/configure b/configure
index 151662f..b8c76fc 100755
--- a/configure
+++ b/configure
@@ -42,8 +42,6 @@ $package options:
   --disable-ipv6                do not build IPv6 support [enabled]
   --enable-iopause-select       prefer select() over poll() for iopause implementation [disabled]
   --enable-tai-clock            assume the system clock is TAI-10 instead of UTC [disabled]
-  --enable-clock                use clock_gettime() instead of gettimeofday() [disabled]
-  --enable-monotonic            count time with CLOCK_MONOTONIC instead of CLOCK_REALTIME
   --with-default-path=PATH      default executable search path [/usr/bin:/bin]
 
 EOF
@@ -241,8 +239,6 @@ slashpackage=false
 ipv6=true
 select=false
 taiclock=false
-clockrt=false
-clockmon=false
 ddefaultpath=/usr/bin:/bin
 defaultpath=$ddefaultpath
 dpathorig=true
@@ -284,10 +280,8 @@ for arg ; do
     --disable-iopause-select|--enable-iopause-select=no) select=false ;;
     --enable-tai-clock|--enable-tai-clock=yes) taiclock=true ;;
     --disable-tai-clock|--enable-tai-clock=no) taiclock=false ;;
-    --enable-clock|--enable-clock=yes) clockrt=true ;;
-    --disable-clock|--enable-clock=no) clockrt=false ;;
-    --enable-monotonic|--enable-monotonic=yes) clockmon=true ;;
-    --disable-monotonic|--enable-monotonic=no) clockmon=false ;;
+    --enable-monotonic|--enable-monotonic=yes) echo "$0: warning: --enable-monotonic is now obsolete" 1>&2 ;;
+    --disable-monotonic|--enable-monotonic=no) ;;
     --with-default-path=*) defaultpath=${arg#*=} ; dpathorig=false ;;
     --without-default-path) defaultpath=$ddefaultpath ; dpathorig=true ;;
     --enable-*|--disable-*|--with-*|--without-*|--*dir=*) ;;
@@ -458,11 +452,6 @@ else
 #undef SKALIBS_TARGET
 #define SKALIBS_TARGET "$target"
 
-#undef SKALIBS_BSD_SUCKS
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__) || defined(__DragonFly__)
-# define SKALIBS_BSD_SUCKS
-#endif
-
 EOF
 
   exec 3>&1
@@ -474,23 +463,19 @@ EOF
 
   hasclock=true
   sysclock_lib=`trylibs clockrt 'clock_gettime()' -lrt` || hasclock=false
-  if $clockrt ; then
-    tainnow_lib=$sysclock_lib
-  else
-    tainnow_lib=
-  fi
+  tainnow_lib=$sysclock_lib
   echo "$sysclock_lib" > $sysdeps/sysclock.lib
   echo "$tainnow_lib" > $sysdeps/tainnow.lib
   echo "#undef ${package_macro_name}_HASCLOCKRT" >> $sysdeps/sysdeps.h
   if $hasclock ; then
     echo 'clockrt: yes' >> $sysdeps/sysdeps
     echo "#define ${package_macro_name}_HASCLOCKRT" >> $sysdeps/sysdeps.h
-    echo >> $sysdeps/sysdeps.h
-    choose cl clockmon CLOCKMON CLOCK_MONOTONIC $sysclock_lib
   else
     echo 'clockrt: no' >> $sysdeps/sysdeps
-    echo >> $sysdeps/sysdeps.h
   fi
+  echo >> $sysdeps/sysdeps.h
+  choose cl clockmon CLOCKMON CLOCK_MONOTONIC $sysclock_lib
+  choose cl clockboot CLOCKBOOT CLOCK_BOOTTIME $sysclock_lib
 
   hasspawn=true
   spawn_lib=`trylibs posixspawn 'posix_spawn()' -lrt` || hasspawn=false
@@ -664,16 +649,6 @@ if $taiclock ; then
 else
   echo "#undef ${package_macro_name}_FLAG_CLOCKISTAI"
 fi
-if $clockrt ; then
-  echo "#define ${package_macro_name}_FLAG_USERT"
-else
-  echo "#undef ${package_macro_name}_FLAG_USERT"
-fi
-if $clockmon ; then
-  echo "#define ${package_macro_name}_FLAG_USEMON"
-else
-  echo "#undef ${package_macro_name}_FLAG_USEMON"
-fi
 if $ipv6 ; then
   echo "#define ${package_macro_name}_FLAG_WANTIPV6"
 else
diff --git a/doc/flags.html b/doc/flags.html
index c901b1c..b74d344 100644
--- a/doc/flags.html
+++ b/doc/flags.html
@@ -175,36 +175,6 @@ and <tt>settimeofday()</tt> interfaces will be used. This is the default,
 and it's usually safe.
 </p>
 
-<a name="usemon"><h3> --enable-monotonic </h3></a>
-
-<p>
- Unless you have an accurate hardware system clock <em>and</em> you set it
-on a linear time scale such as TAI-10 instead of UTC (see above), it is
-generally a bad idea to trust the system clock for precise time interval
-measurements. Single Unix recommends the use of <tt>clock_gettime()</tt>
-with the CLOCK_MONOTONIC option to do such measurements: a stopwatch, not
-a wall clock. However:
-</p>
-
-<ul>
- <li> CLOCK_MONOTONIC is even less portable than CLOCK_REALTIME. </li>
- <li> It's a bit tricky to emulate absolute time calculations based on
-CLOCK_MONOTONIC. </li>
-</ul>
-
-<p>
- If <tt>--enable-monotonic</tt> is set, then the absolute time given by the
-<tt>tain_now()</tt> call will be computed with CLOCK_MONOTONIC. This
-will ensure precise time arithmetic but may drift away from the system
-clock.
-</p>
-
-<p>
- Otherwise, <tt>tain_now()</tt> will
-return a time based on the system clock, and not use CLOCK_MONOTONIC.
-This is the default.
-</p>
-
 <a name="noipv6"><h3> --disable-ipv6 </h3></a>
 
 <p>
diff --git a/doc/libstddjb/tai.html b/doc/libstddjb/tai.html
index 8440c78..3826e80 100644
--- a/doc/libstddjb/tai.html
+++ b/doc/libstddjb/tai.html
@@ -130,12 +130,9 @@ it fails.
 
 <p>
 <code> int sysclock_get (tain_t *a) </code> <br />
-Reads the current value of the system clock into *<em>a</em>, with
-a 1-nanosecond (resp. 1-microsecond ) precision if skalibs has been
-configured with (resp. without) the
-<a href="../flags.html#usert">--enable-clock</a> option.
-Returns 1 if it succeeds or 0 (and sets errno) if it
-fails. Note that despite being a <tt>tain_t</tt>, *<em>a</em>
+Reads the current value of the system clock (as in CLOCK_REALTIME) into *<em>a</em>.
+Returns 1 if it succeeds or 0 (and sets errno) if it fails.
+Note that despite being a <tt>tain_t</tt>, *<em>a</em>
 <strong>does not contain a TAI value</strong> - it only contains
 an internal, Y2038-safe representation of the value of the system
 clock, which should be either TAI-10 or UTC. You should not use
@@ -150,103 +147,106 @@ function directly unless you know exactly what you are doing.
 </p>
 
 <p>
-<code> int tain_sysclock (tain_t *a) </code> <br />
-Reads the current time into *<em>a</em>, as a TAI64N value,
-with a 1-nanosecond (resp. 1-microsecond) precision if skalibs
-has been configured with (resp. without) the
-<a href="../flags.html#usert">--enable-clock</a>
-option. Returns 1 if it succeeds or 0 (and sets errno) if it
-fails.
- Here <em>a</em> contains a valid TAI64N stamp, no matter what the
+<code> int tain_wallclock_read (tain_t *a) </code> <br />
+Reads the current time into *<em>a</em>, as a TAI64N value.
+Returns 1 if it succeeds or 0 (and sets errno) if it fails.
+Here <em>a</em> contains a valid TAI64N stamp, no matter what the
 system clock is set to: arithmetic operations can be performed
 on it.
 </p>
 
 <p>
 <code> int tain_setnow (tain_t const *a) </code> <br />
-Sets the current time to *<em>a</em>, with a 1-nanosecond
-(resp. 1-microsecond) precision if skalibs has been configured
-with (resp. without) the
-<a href="../flags.html#usert">--enable-clock</a>
-option. Returns 1 if it succeeds or 0 (and sets errno) if it
-fails. <em>a</em> must contain a valid TAI64N stamp; proper
+Sets the current time to *<em>a</em>.
+Returns 1 if it succeeds or 0 (and sets errno) if it fails.
+<em>a</em> must contain a valid TAI64N stamp; proper
 operations will be automatically run to convert that stamp into
 the right format for the system clock.
 </p>
 
+<p>
+<code> void tain_now_set_wallclock (void) </code> <br />
+Tells skalibs that future invocations of <tt>tain_now()</tt>
+(see below) should use a wall clock, i.e. the system time
+as returned by <tt>clock_gettime(CLOCK_REALTIME)</tt> or
+<tt>gettimeofday()</tt>. This is the default: it is not necessary
+to call this function before invoking <tt>tain_now()</tt> at the
+start of a program.
+</p>
+
 <h3> Stopwatch operations </h3>
 
 <p>
- The following 3 operations are only defined if your system
-provides the
+The following two operations can only succeed if your system provides the
 <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_gettime.html">clock_gettime()</a>
-primitive with the CLOCK_MONOTONIC option.
+primitive with at least one of the CLOCK_MONOTONIC or CLOCK_BOOTTIME clocks.
+Otherwise, they will fail with errno set to ENOSYS.
 </p>
 
 <p>
-<code> int tain_clockmon_init (tain_t *offset) </code> <br />
-Initializes a stopwatch in *<em>offset</em>. The actual value of
+<code> int tain_stopwatch_init (clock_t cl, tain_t *offset) </code> <br />
+Initializes a stopwatch in *<em>offset</em>, using a clock named <em>cl</em>.
+Typically, <em>cl</em> is something like CLOCK_MONOTONIC, when it is defined
+by the system. The actual value of
 *<em>offset</em> is meaningless to the user; <em>offset</em>'s only
-use is to be given as a second parameter to <tt>tain_clockmon()</tt>.
+use is to be given as a second parameter to <tt>tain_stopwatch_read()</tt>.
 The function returns 1 if it succeeds or 0 (and sets errno) if it fails.
 </p>
 
 <p>
- What <tt>tain_clockmon_init()</tt> does is synchronize the "stopwatch
-clock" (CLOCK_MONOTONIC) to the system clock. Right after
-<tt>tain_clockmon_init()</tt> has been called, the absolute times given
-by <tt>tain_clockmon()</tt> and <tt>tain_sysclock()</tt> are similar. Then,
-depending on the accuracy of the system clock, a drift may appear; calling
-<tt>tain_clockmon_init()</tt> again resets that drift to zero.
+ What <tt>tain_stopwatch_init()</tt> does is synchronize the "stopwatch
+clock" to the system clock. Right after <tt>tain_stopwatch_init()</tt>
+has been called, the absolute times given
+by <tt>tain_stopwatch_read()</tt> and <tt>tain_wallclock_read()</tt> are
+the same. Then, depending on the accuracy of the system clock, a drift
+may appear; calling <tt>tain_stopwatch_init()</tt> again resets that drift
+to zero.
 </p>
 
 <p>
-<code> int tain_clockmon (tain_t *a, tain_t const *offset) </code> <br />
+<code> int tain_stopwatch_read (tain_t *a, clock_t cl, tain_t const *offset) </code> <br />
  Gives the absolute time, as a TAI64N value, in *<em>a</em>. This
 absolute time is computed as a linear increase (as measured with
-CLOCK_MONOTONIC) since the last time <tt>tain_clockmon_init()</tt>
-was called with parameter <em>offset</em>. <tt>tain_clockmon()</tt>
+the <em>cl</em> clock, which should be a monotonic clock such as
+CLOCK_MONOTONIC) since the last time <tt>tain_stopwatch_init()</tt>
+was called with parameter <em>offset</em>. <tt>tain_stopwatch_read()</tt>
 guarantees precise time interval measurements; however, the time it
-gives can slightly differ from the result of <tt>tain_sysclock()</tt>.
+gives can slightly differ from the result of <tt>tain_wallclock_read()</tt>.
 The function returns 1 if it succeeds or 0 (and sets errno) if it fails.
 </p>
 
-<h3> All-purpose time reading </h3>
-
 <p>
-<code> int tain_init (void) </code> <br />
-If skalibs has been configured with the
-<a href="../flags.html#usemon">--enable-monotonic</a> option: this
-function initializes a process-global stopwatch, that future
-<tt>tain_now</tt> invocations will depend on.
-Without the <a href="../flags.html#usemon">--enable-monotonic</a> option: this
-function does nothing.
-The function returns 1 if it succeeds or 0 (and sets errno) if it fails.
+<code> void tain_now_set_stopwatch (void) </code> <br />
+Tells skalibs that future invocations of <tt>tain_now()</tt>
+(see below) should use a stopwatch, i.e. the system time
+as returned by <tt>clock_gettime(CLOCK_MONOTONIC)</tt> or similar,
+if supported by the system. This is useful when it is more important
+for a program to compute unchanging time intervals no matter what the
+system clock does, than to display absolute time that is in sync with a
+human view of time (which is the cause and reason of most system clock
+jumps). <br />
+If no monotonic clock is supported by the system, this function does
+nothing (and <tt>tain_now()</tt> will keep using a wall clock).
 </p>
 
+<h3> All-purpose time reading </h3>
+
 <p>
 <code> int tain_now (tain_t *a) </code> <br />
 Writes the current time, as a TAI value, to *<em>a</em>. This is the
-function you should use to read time by default. It returns 1 if it succeeds or
+function you should use by default. It returns 1 if it succeeds or
 0 (and sets errno) if it fails.
 </p>
 
 <p>
- If skalibs has been configured with the
-<a href="../flags.html#usemon">--enable-monotonic</a> option:
-<tt>tain_now()</tt> is computed as a linear increase from the last time
-<tt>tain_init()</tt> was called. (If <tt>tain_init()</tt> has never
-been called before, the first invocation of <tt>tain_now()</tt>
-automatically calls <tt>tain_init()</tt>.)
- Without the <a href="../flags.html#usemon">--enable-monotonic</a> option:
-<tt>tain_now()</tt> is the same as <tt>tain_sysclock()</tt>.
-</p>
-
-<p>
- If the above is unclear to you: just use <tt>tain_now()</tt>
-everytime you need to read time, and you will always get a reasonable
-approximation of the current time, in a format suited for arithmetic
-computations.
+ <tt>tain_now()</tt> relies on the concept that there is One True Time Source
+for the process, and that is where it reads time from. By default, the
+One True Time Source is the system clock (a wall clock), and <tt>tain_now()</tt>
+is actually an alias to <tt>tain_wallclock_read()</tt>. At the start of a
+program, calling <tt>tain_now_set_stopwatch()</tt> will define a monotonic
+clock (if supported by the system) as the One True Time Source, which will
+make <tt>tain_now()</tt> resistant to system clock jumps, but will also
+make it unsuitable for timestamping.
 </p>
 
 <h3> Converting to/from libc representations </h3>
diff --git a/doc/upgrade.html b/doc/upgrade.html
index f56629e..76c1973 100644
--- a/doc/upgrade.html
+++ b/doc/upgrade.html
@@ -23,6 +23,12 @@
  <li> The configure script now emulates autotools-created configure scripts
 more closely. In particular, it's now possible to declare an out-of-path
 compiler in <tt>CC</tt>. </li>
+ <li> <tt>tain_*</tt> functions dealing with wall clocks and stopwatches
+have been refactored. The <tt>--enable-clock</tt> and </tt>--enable-monotonic</tt>
+configure switches have been removed. <tt>tain_now()</tt> can now be told at run
+time to use a wall clock (default, or via <tt>tain_now_set_wallclock()</tt>) or a
+stopwatch (via <tt>tain_now_set_stopwatch()</tt>), instead of it being fixed at
+build time. </li>
 </ul>
 
 <h2> in 2.8.1.0 </h2>
diff --git a/package/deps.mak b/package/deps.mak
index 4fc5850..24d7436 100644
--- a/package/deps.mak
+++ b/package/deps.mak
@@ -598,8 +598,8 @@ src/libstddjb/sysclock_from_ltm64.o src/libstddjb/sysclock_from_ltm64.lo: src/li
 src/libstddjb/sysclock_from_tai.o src/libstddjb/sysclock_from_tai.lo: src/libstddjb/sysclock_from_tai.c src/include/skalibs/config.h src/include/skalibs/djbtime.h src/include/skalibs/tai.h
 src/libstddjb/sysclock_from_tain.o src/libstddjb/sysclock_from_tain.lo: src/libstddjb/sysclock_from_tain.c src/include/skalibs/tai.h
 src/libstddjb/sysclock_from_utc.o src/libstddjb/sysclock_from_utc.lo: src/libstddjb/sysclock_from_utc.c src/include/skalibs/config.h src/include/skalibs/djbtime.h src/include/skalibs/uint64.h
-src/libstddjb/sysclock_get.o src/libstddjb/sysclock_get.lo: src/libstddjb/sysclock_get.c src/include/skalibs/config.h src/include/skalibs/sysdeps.h src/include/skalibs/tai.h
-src/libstddjb/sysclock_set.o src/libstddjb/sysclock_set.lo: src/libstddjb/sysclock_set.c src/include/skalibs/config.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h src/include/skalibs/tai.h
+src/libstddjb/sysclock_get.o src/libstddjb/sysclock_get.lo: src/libstddjb/sysclock_get.c src/include/skalibs/sysdeps.h src/include/skalibs/tai.h
+src/libstddjb/sysclock_set.o src/libstddjb/sysclock_set.lo: src/libstddjb/sysclock_set.c src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h src/include/skalibs/tai.h
 src/libstddjb/tai_add.o src/libstddjb/tai_add.lo: src/libstddjb/tai_add.c src/include/skalibs/tai.h
 src/libstddjb/tai_from_localtm.o src/libstddjb/tai_from_localtm.lo: src/libstddjb/tai_from_localtm.c src/include/skalibs/djbtime.h src/include/skalibs/uint64.h
 src/libstddjb/tai_from_ltm64.o src/libstddjb/tai_from_ltm64.lo: src/libstddjb/tai_from_ltm64.c src/libstddjb/djbtime-internal.h src/include/skalibs/djbtime.h
@@ -615,7 +615,6 @@ src/libstddjb/tai_unpack_little.o src/libstddjb/tai_unpack_little.lo: src/libstd
 src/libstddjb/tain_add.o src/libstddjb/tain_add.lo: src/libstddjb/tain_add.c src/include/skalibs/tai.h
 src/libstddjb/tain_addsec.o src/libstddjb/tain_addsec.lo: src/libstddjb/tain_addsec.c src/include/skalibs/tai.h src/include/skalibs/uint64.h
 src/libstddjb/tain_approx.o src/libstddjb/tain_approx.lo: src/libstddjb/tain_approx.c src/include/skalibs/tai.h
-src/libstddjb/tain_clockmon.o src/libstddjb/tain_clockmon.lo: src/libstddjb/tain_clockmon.c src/include/skalibs/sysdeps.h src/include/skalibs/tai.h
 src/libstddjb/tain_fmt.o src/libstddjb/tain_fmt.lo: src/libstddjb/tain_fmt.c src/include/skalibs/fmtscan.h src/include/skalibs/tai.h
 src/libstddjb/tain_frac.o src/libstddjb/tain_frac.lo: src/libstddjb/tain_frac.c src/include/skalibs/tai.h
 src/libstddjb/tain_from_localtmn.o src/libstddjb/tain_from_localtmn.lo: src/libstddjb/tain_from_localtmn.c src/include/skalibs/djbtime.h
@@ -630,19 +629,22 @@ src/libstddjb/tain_half.o src/libstddjb/tain_half.lo: src/libstddjb/tain_half.c
 src/libstddjb/tain_infinite_relative.o src/libstddjb/tain_infinite_relative.lo: src/libstddjb/tain_infinite_relative.c src/include/skalibs/tai.h
 src/libstddjb/tain_less.o src/libstddjb/tain_less.lo: src/libstddjb/tain_less.c src/include/skalibs/tai.h
 src/libstddjb/tain_nano500.o src/libstddjb/tain_nano500.lo: src/libstddjb/tain_nano500.c src/include/skalibs/tai.h
-src/libstddjb/tain_now.o src/libstddjb/tain_now.lo: src/libstddjb/tain_now.c src/include/skalibs/config.h src/include/skalibs/sysdeps.h src/include/skalibs/tai.h
+src/libstddjb/tain_now.o src/libstddjb/tain_now.lo: src/libstddjb/tain_now.c src/include/skalibs/tai.h
+src/libstddjb/tain_now_set_stopwatch.o src/libstddjb/tain_now_set_stopwatch.lo: src/libstddjb/tain_now_set_stopwatch.c src/include/skalibs/tai.h
+src/libstddjb/tain_now_set_wallclock.o src/libstddjb/tain_now_set_wallclock.lo: src/libstddjb/tain_now_set_wallclock.c src/include/skalibs/tai.h
 src/libstddjb/tain_pack.o src/libstddjb/tain_pack.lo: src/libstddjb/tain_pack.c src/include/skalibs/tai.h src/include/skalibs/uint32.h
 src/libstddjb/tain_pack_little.o src/libstddjb/tain_pack_little.lo: src/libstddjb/tain_pack_little.c src/include/skalibs/tai.h src/include/skalibs/uint32.h
 src/libstddjb/tain_relative_from_timespec.o src/libstddjb/tain_relative_from_timespec.lo: src/libstddjb/tain_relative_from_timespec.c src/include/skalibs/tai.h
 src/libstddjb/tain_relative_from_timeval.o src/libstddjb/tain_relative_from_timeval.lo: src/libstddjb/tain_relative_from_timeval.c src/include/skalibs/tai.h
 src/libstddjb/tain_scan.o src/libstddjb/tain_scan.lo: src/libstddjb/tain_scan.c src/include/skalibs/fmtscan.h src/include/skalibs/tai.h
 src/libstddjb/tain_setnow.o src/libstddjb/tain_setnow.lo: src/libstddjb/tain_setnow.c src/include/skalibs/tai.h
+src/libstddjb/tain_stopwatch.o src/libstddjb/tain_stopwatch.lo: src/libstddjb/tain_stopwatch.c src/include/skalibs/sysdeps.h src/include/skalibs/tai.h
 src/libstddjb/tain_sub.o src/libstddjb/tain_sub.lo: src/libstddjb/tain_sub.c src/include/skalibs/tai.h
-src/libstddjb/tain_sysclock.o src/libstddjb/tain_sysclock.lo: src/libstddjb/tain_sysclock.c src/include/skalibs/tai.h
 src/libstddjb/tain_to_millisecs.o src/libstddjb/tain_to_millisecs.lo: src/libstddjb/tain_to_millisecs.c src/include/skalibs/tai.h src/include/skalibs/uint64.h
 src/libstddjb/tain_ulong.o src/libstddjb/tain_ulong.lo: src/libstddjb/tain_ulong.c src/include/skalibs/tai.h
 src/libstddjb/tain_unpack.o src/libstddjb/tain_unpack.lo: src/libstddjb/tain_unpack.c src/include/skalibs/tai.h src/include/skalibs/uint32.h
 src/libstddjb/tain_unpack_little.o src/libstddjb/tain_unpack_little.lo: src/libstddjb/tain_unpack_little.c src/include/skalibs/tai.h src/include/skalibs/uint32.h
+src/libstddjb/tain_wallclock_read.o src/libstddjb/tain_wallclock_read.lo: src/libstddjb/tain_wallclock_read.c src/include/skalibs/tai.h
 src/libstddjb/tain_zero.o src/libstddjb/tain_zero.lo: src/libstddjb/tain_zero.c src/include/skalibs/tai.h
 src/libstddjb/time_from_tai.o src/libstddjb/time_from_tai.lo: src/libstddjb/time_from_tai.c src/include/skalibs/bsdsnowflake.h src/include/skalibs/sysdeps.h src/include/skalibs/tai.h src/include/skalibs/uint64.h
 src/libstddjb/time_from_tai_relative.o src/libstddjb/time_from_tai_relative.lo: src/libstddjb/time_from_tai_relative.c src/include/skalibs/bsdsnowflake.h src/include/skalibs/sysdeps.h src/include/skalibs/tai.h
diff --git a/src/include/skalibs/tai.h b/src/include/skalibs/tai.h
index f3699ce..2bdf524 100644
--- a/src/include/skalibs/tai.h
+++ b/src/include/skalibs/tai.h
@@ -86,19 +86,24 @@ extern int timespec_from_tain_relative (struct timespec *, tain_t const *) ;
 extern int timespec_from_tain (struct timespec *, tain_t const *) ;
 extern int timespec_sysclock_from_tain (struct timespec *, tain_t const *) ;
 
-extern int sysclock_get (tain_t *) ;
-extern int tain_sysclock (tain_t *) ;
+typedef int tain_clockread_func_t (tain_t *) ;
+typedef tain_clockread_func_t *tain_clockread_func_t_ref ;
+
 extern int tain_from_sysclock (tain_t *, tain_t const *) ;
 extern int sysclock_from_tain (tain_t *, tain_t const *) ;
-#define tain_sysclock_g() tain_sysclock(&STAMP)
-extern int tain_clockmon_init (tain_t *) ;
-extern int tain_clockmon (tain_t *, tain_t const *) ;
-#define tain_clockmon_g(offset) tain_clockmon(&STAMP, (offset))
-extern int tain_init (void) ;
-extern int tain_now (tain_t *) ;
-#define tain_now_g() tain_now(&STAMP)
+extern tain_clockread_func_t sysclock_get ;
+extern tain_clockread_func_t tain_wallclock_read ;
+#define tain_wallclock_read_g() tain_wallclock_read(&STAMP)
+extern int tain_stopwatch_init (clock_t, tain_t *) ;
+extern int tain_stopwatch_read (tain_t *, clock_t, tain_t const *) ;
+#define tain_stopwatch_read_g(cl, offset) tain_stopwatch_read(&STAMP, (cl), offset)
+extern tain_clockread_func_t_ref tain_now ;
+#define tain_now_g() (*tain_now)(&STAMP)
 #define tain_copynow(t) (*(t) = STAMP)
 
+extern void tain_now_set_wallclock (void) ;
+extern void tain_now_set_stopwatch (void) ;
+
 extern int sysclock_set (tain_t const *) ;
 extern int tain_setnow (tain_t const *) ;
 
diff --git a/src/libstddjb/sysclock_get.c b/src/libstddjb/sysclock_get.c
index 3d14f96..6c5041d 100644
--- a/src/libstddjb/sysclock_get.c
+++ b/src/libstddjb/sysclock_get.c
@@ -1,17 +1,9 @@
 /* ISC license. */
 
-#include <skalibs/config.h>
 #include <skalibs/sysdeps.h>
 #include <skalibs/tai.h>
 
-#ifdef SKALIBS_FLAG_USERT
-# ifndef SKALIBS_HASCLOCKRT
-#  undef SKALIBS_FLAG_USERT
-#  warning "SKALIBS_FLAG_USERT set but SKALIBS_HASCLOCKRT not found. Clearing SKALIBS_FLAG_USERT."
-# endif
-#endif
-
-#ifdef SKALIBS_FLAG_USERT
+#ifdef SKALIBS_HASCLOCKRT
 
 #include <time.h>
 
diff --git a/src/libstddjb/sysclock_set.c b/src/libstddjb/sysclock_set.c
index 0ec51c6..57e2abe 100644
--- a/src/libstddjb/sysclock_set.c
+++ b/src/libstddjb/sysclock_set.c
@@ -2,24 +2,16 @@
 
 /* MT-unsafe */
 
-#include <skalibs/config.h>
 #include <skalibs/sysdeps.h>
 
-#ifdef SKALIBS_FLAG_USERT
-# ifndef SKALIBS_HASCLOCKRT
-#  undef SKALIBS_FLAG_USERT
-#  warning "SKALIBS_FLAG_USERT set but SKALIBS_HASCLOCKRT not found. Clearing SKALIBS_FLAG_USERT."
-# endif
-#endif
-
-#ifndef SKALIBS_FLAG_USERT
+#ifndef SKALIBS_HASCLOCKRT
 # ifndef SKALIBS_HASSETTIMEOFDAY
-#  error "SKALIBS_FLAG_USERT clear but SKALIBS_HASSETTIMEOFDAY not found. How do your set your system clock?"
+#  error "neither clockrt nor settimeofday sysdeps are present. How do your set your system clock?"
 # endif
 #endif
 
 
-#ifdef SKALIBS_FLAG_USERT
+#ifdef SKALIBS_HASCLOCKRT
 
 #include <time.h>
 #include <skalibs/tai.h>
diff --git a/src/libstddjb/tain_clockmon.c b/src/libstddjb/tain_clockmon.c
deleted file mode 100644
index f14cd31..0000000
--- a/src/libstddjb/tain_clockmon.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/* ISC license. */
-
-#include <skalibs/sysdeps.h>
-#include <skalibs/tai.h>
-
-#ifdef SKALIBS_HASCLOCKMON
-
-#include <time.h>
-
-int tain_clockmon_init (tain_t *offset)
-{
-  tain_t a, b ;
-  struct timespec ts ;
-  if (!tain_sysclock(&a)) return 0 ;
-  if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) return 0 ;
-  if (!tain_from_timespec(&b, &ts)) return 0 ;
-  tain_add(&a, &a, &tain_nano500) ;
-  tain_sub(offset, &a, &b) ;
-  return 1 ;
-}
-
-int tain_clockmon (tain_t *a, tain_t const *offset)
-{
-  struct timespec ts ;
-  if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) return 0 ;
-  if (!tain_from_timespec(a, &ts)) return 0 ;
-  tain_add(a, a, offset) ;
-  return 1 ;
-}
-
-#else
-
-#include <errno.h>
-
-int tain_clockmon_init (tain_t *offset)
-{
-  (void)offset ;
-  return (errno = ENOSYS, 0) ;
-}
-
-int tain_clockmon (tain_t *a, tain_t const *offset)
-{
-  (void)a ; (void)offset ;
-  return (errno = ENOSYS, 0) ;
-}
-
-#endif
diff --git a/src/libstddjb/tain_now.c b/src/libstddjb/tain_now.c
index 157087a..d6625d6 100644
--- a/src/libstddjb/tain_now.c
+++ b/src/libstddjb/tain_now.c
@@ -2,48 +2,6 @@
 
 /* MT-unsafe */
 
-#include <skalibs/config.h>
-#include <skalibs/sysdeps.h>
 #include <skalibs/tai.h>
 
-#ifdef SKALIBS_FLAG_USEMON
-# ifndef SKALIBS_HASCLOCKMON
-#  undef SKALIBS_FLAG_USEMON
-#  warning "SKALIBS_FLAG_USEMON set but SKALIBS_HASCLOCKMON not found. Clearing SKALIBS_FLAG_USEMON."
-# endif
-#endif
-
-
-#ifdef SKALIBS_FLAG_USEMON
-
-static tain_t offset ;
-
-int tain_init ()
-{
-  return tain_clockmon_init(&offset) ;
-}
-
-int tain_now (tain_t *a)
-{
-  static int initted = 0 ;
-  if (!initted)
-  {
-    if (!tain_clockmon_init(&offset)) return 0 ;
-    initted = 1 ;
-  }
-  return tain_clockmon(a, &offset) ;
-}
-
-#else
-
-int tain_init ()
-{
-  return 1 ;
-}
-
-int tain_now (tain_t *a)
-{
-  return tain_sysclock(a) ;
-}
-
-#endif
+tain_clockread_func_t_ref tain_now = &tain_wallclock_read ;
diff --git a/src/libstddjb/tain_now_set_stopwatch.c b/src/libstddjb/tain_now_set_stopwatch.c
new file mode 100644
index 0000000..184a40a
--- /dev/null
+++ b/src/libstddjb/tain_now_set_stopwatch.c
@@ -0,0 +1,36 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/tai.h>
+
+#if defined(SKALIBS_HAS_CLOCKRT) && (defined(SKALIBS_HAS_CLOCKMON) || defined(SKALIBS_HAS_CLOCKBOOT))
+
+#include <time.h>
+
+#ifdef SKALIBS_HAS_CLOCKMON
+# define SKALIBS_STOPWATCH CLOCK_MONOTONIC
+#else
+# define SKALIBS_STOPWATCH CLOCK_BOOTTIME
+#endif
+
+static tain_t offset ;
+
+static int tain_now_stopwatch (tain_t *a)
+{
+  return tain_stopwatch_read(a, SKALIBS_STOPWATCH, &offset) ;
+}
+
+void tain_now_set_stopwatch (void)
+{
+  if (!tain_stopwatch_init(SKALIBS_STOPWATCH, &offset)) return ;
+  tain_now = &tain_now_stopwatch ;
+}
+
+#else
+
+void tain_now_set_stopwatch (void)
+{
+}
+
+#endif
diff --git a/src/libstddjb/tain_now_set_wallclock.c b/src/libstddjb/tain_now_set_wallclock.c
new file mode 100644
index 0000000..a3d8b61
--- /dev/null
+++ b/src/libstddjb/tain_now_set_wallclock.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+/* MT-unsafe */
+
+#include <skalibs/tai.h>
+
+void tain_now_set_wallclock (void)
+{
+  tain_now = &tain_wallclock_read ;
+}
diff --git a/src/libstddjb/tain_stopwatch.c b/src/libstddjb/tain_stopwatch.c
new file mode 100644
index 0000000..2bb4974
--- /dev/null
+++ b/src/libstddjb/tain_stopwatch.c
@@ -0,0 +1,50 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+#include <skalibs/tai.h>
+
+#if defined(SKALIBS_HASCLOCKRT) && (defined(SKALIBS_HASCLOCKMON) || defined(SKALIBS_HASCLOCKBOOT))
+
+#include <time.h>
+
+int tain_stopwatch_init (clock_t cl, tain_t *offset)
+{
+  tain_t a, b ;
+  struct timespec ts ;
+  if (!tain_wallclock_read(&a)) return 0 ;
+  if (clock_gettime(cl, &ts) < 0) return 0 ;
+  if (!tain_from_timespec(&b, &ts)) return 0 ;
+  tain_add(&a, &a, &tain_nano500) ;
+  tain_sub(offset, &a, &b) ;
+  return 1 ;
+}
+
+int tain_stopwatch_read (tain_t *a, clock_t cl, tain_t const *offset)
+{
+  struct timespec ts ;
+  if (clock_gettime(cl, &ts) < 0) return 0 ;
+  if (!tain_from_timespec(a, &ts)) return 0 ;
+  tain_add(a, a, offset) ;
+  return 1 ;
+}
+
+#else
+
+#include <errno.h>
+
+int tain_stopwatch_init (clock_t cl, tain_t *offset)
+{
+  (void)cl ;
+  (void)offset ;
+  return (errno = ENOSYS, 0) ;
+}
+
+int tain_stopwatch_read (tain_t *a, clock_t cl, tain_t const *offset)
+{
+  (void)a ;
+  (void)cl ;
+  (void)offset ;
+  return (errno = ENOSYS, 0) ;
+}
+
+#endif
diff --git a/src/libstddjb/tain_sysclock.c b/src/libstddjb/tain_wallclock_read.c
index 3b98eb1..96ed861 100644
--- a/src/libstddjb/tain_sysclock.c
+++ b/src/libstddjb/tain_wallclock_read.c
@@ -2,7 +2,7 @@
 
 #include <skalibs/tai.h>
 
-int tain_sysclock (tain_t *a)
+int tain_wallclock_read (tain_t *a)
 {
   tain_t aa ;
   if (!sysclock_get(&aa)) return 0 ;
diff --git a/src/libstddjb/timestamp_r.c b/src/libstddjb/timestamp_r.c
index 6eb8ab7..46be7a4 100644
--- a/src/libstddjb/timestamp_r.c
+++ b/src/libstddjb/timestamp_r.c
@@ -4,7 +4,7 @@
 
 int timestamp_r (char *s, tain_t *stamp)
 {
-  if (!tain_sysclock(stamp)) return 0 ;
+  if (!tain_wallclock_read(stamp)) return 0 ;
   timestamp_fmt(s, stamp) ;
   return 1 ;
 }
diff --git a/src/sysdeps/tryclockboot.c b/src/sysdeps/tryclockboot.c
new file mode 100644
index 0000000..de8bf5c
--- /dev/null
+++ b/src/sysdeps/tryclockboot.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <time.h>
+
+int main (void)
+{
+  struct timespec ts ;
+  if (clock_gettime(CLOCK_BOOTTIME, &ts) < 0) return 111 ;
+  return 0 ;
+}