On Thu, Dec 14, 2017 at 06:47:02PM -0600, Scott Cheloha wrote:
> Hi,
> 
> Attached is a diff adding a new clockid, CLOCK_BOOTTIME, for use with
> clock_gettime(2).  The value of CLOCK_BOOTTIME is the time elapsed
> since the system booted, i.e. the system uptime.  The diff puts it to
> use in top(1), w(1), and snmpd(8).
> 
> CLOCK_BOOTTIME originated in Linux in the 2.6.39 kernel [1, 2].
> 
> The base motivation for adding CLOCK_BOOTTIME to OpenBSD is that there
> is currently no direct interface for userland to query the system
> uptime, i.e., the time elapsed since the machine was last (re)booted.
> 
> We have several callers using the kern.boottime sysctl, but all of
> them immediately subtract the result from the current time of day to
> derive the system uptime.  This is is (a) cumbersome, and (b) involves
> a race with settimeofday(2), etc.
> 
> We could add a new sysctl, but sysctl(3) itself is cumbersome,
> especially when compared to clock_gettime(2).
> 
> Although CLOCK_MONOTONIC is currently implemented with nanouptime(9)
> and is thus an interface to the system uptime, this is only coincidentally
> so.  The standard notes that the value returned by CLOCK_MONOTONIC is
> meaningless in isolation: it is only portably useful for interval
> measurement.  Overloading CLOCK_MONOTONIC as an interface to the system
> uptime would confuse the purpose of the clock, promote the creation of non-
> portable code, and prevent us from changing the clock's implementation
> in the future.
> 
> On top of enriching base with a nice interface to the system uptime,
> this diff also makes CLOCK_BOOTTIME available to ports with the same
> semantics it has in Linux.  CLOCK_BOOTTIME has been available in Linux
> for over five years, so there are almost certainly ports that can make
> use of it.
> 
> The diff in its current form is the result of discussion and revision
> with guenther@, jca@, and tb@.  All gave their ok.
> 
> Thoughts and feedback?
> 


No objections, you can add me to the ok list...

-ml

> --
> Scott Cheloha
> 
> [1] https://marc.info/?l=linux-kernel&m=129783004314557&w=2
> [2] 
> https://github.com/torvalds/linux/commit/420c1c572d4ceaa2f37b6311b7017ac6cf049fe2
> 
> Index: lib/libc/sys/clock_gettime.2
> ===================================================================
> RCS file: /cvs/src/lib/libc/sys/clock_gettime.2,v
> retrieving revision 1.27
> diff -u -p -r1.27 clock_gettime.2
> --- lib/libc/sys/clock_gettime.2      10 Sep 2015 17:55:21 -0000      1.27
> +++ lib/libc/sys/clock_gettime.2      15 Dec 2017 00:43:29 -0000
> @@ -73,6 +73,9 @@ time that increments as a wall clock sho
>  is meaningless and cannot jump,
>  providing accurate realtime interval measurement,
>  even across suspend and resume
> +.It Dv CLOCK_BOOTTIME
> +time whose absolute value is the time that has elapsed since the
> +system was booted
>  .It Dv CLOCK_UPTIME
>  time whose absolute value is the time the system has been running
>  and not suspended,
> @@ -157,8 +160,10 @@ functions conform to
>  .St -p1003.1-2008 .
>  .Pp
>  The
> +.Dv CLOCK_BOOTTIME
> +and
>  .Dv CLOCK_UPTIME
> -clock is an extension to that.
> +clocks are extensions to that.
>  .Sh HISTORY
>  The
>  .Dv CLOCK_PROCESS_CPUTIME_ID
> @@ -174,3 +179,11 @@ and was added to
>  .Ox
>  in
>  .Ox 5.5 .
> +The
> +.Dv CLOCK_BOOTTIME
> +clock first appeared in
> +Linux 2.6.39
> +and was added to
> +.Ox
> +in
> +.Ox 6.3 .
> Index: sys/kern/kern_time.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/kern_time.c,v
> retrieving revision 1.99
> diff -u -p -r1.99 kern_time.c
> --- sys/kern/kern_time.c      24 Jan 2017 00:58:55 -0000      1.99
> +++ sys/kern/kern_time.c      15 Dec 2017 00:43:29 -0000
> @@ -124,6 +124,7 @@ clock_gettime(struct proc *p, clockid_t 
>               bintime2timespec(&bt, tp);
>               break;
>       case CLOCK_MONOTONIC:
> +     case CLOCK_BOOTTIME:
>               nanouptime(tp);
>               break;
>       case CLOCK_PROCESS_CPUTIME_ID:
> @@ -223,6 +224,7 @@ sys_clock_getres(struct proc *p, void *v
>       switch (clock_id) {
>       case CLOCK_REALTIME:
>       case CLOCK_MONOTONIC:
> +     case CLOCK_BOOTTIME:
>       case CLOCK_UPTIME:
>       case CLOCK_PROCESS_CPUTIME_ID:
>       case CLOCK_THREAD_CPUTIME_ID:
> Index: sys/sys/_time.h
> ===================================================================
> RCS file: /cvs/src/sys/sys/_time.h,v
> retrieving revision 1.8
> diff -u -p -r1.8 _time.h
> --- sys/sys/_time.h   3 Sep 2016 15:06:06 -0000       1.8
> +++ sys/sys/_time.h   15 Dec 2017 00:43:29 -0000
> @@ -37,6 +37,7 @@
>  #define CLOCK_MONOTONIC                      3
>  #define CLOCK_THREAD_CPUTIME_ID              4
>  #define CLOCK_UPTIME                 5
> +#define CLOCK_BOOTTIME                       6
>  
>  #if __BSD_VISIBLE
>  /*
> Index: usr.bin/w/w.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/w/w.c,v
> retrieving revision 1.64
> diff -u -p -r1.64 w.c
> --- usr.bin/w/w.c     14 Dec 2017 18:03:03 -0000      1.64
> +++ usr.bin/w/w.c     15 Dec 2017 00:43:29 -0000
> @@ -66,7 +66,6 @@
>  
>  #include "extern.h"
>  
> -struct timeval       boottime;
>  struct utmp  utmp;
>  struct winsize       ws;
>  kvm_t               *kd;
> @@ -426,10 +425,9 @@ static void
>  pr_header(time_t *nowp, int nusers)
>  {
>       double avenrun[3];
> +     struct timespec boottime;
>       time_t uptime;
>       int days, hrs, i, mins;
> -     int mib[2];
> -     size_t size;
>       char buf[256];
>  
>       /*
> @@ -441,13 +439,9 @@ pr_header(time_t *nowp, int nusers)
>  
>       /*
>        * Print how long system has been up.
> -      * (Found by getting "boottime" from the kernel)
>        */
> -     mib[0] = CTL_KERN;
> -     mib[1] = KERN_BOOTTIME;
> -     size = sizeof(boottime);
> -     if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1) {
> -             uptime = now - boottime.tv_sec;
> +     if (clock_gettime(CLOCK_BOOTTIME, &boottime) != -1) {
> +             uptime = boottime.tv_sec;
>               if (uptime > 59) {
>                       uptime += 30;
>                       days = uptime / SECSPERDAY;
> Index: usr.bin/top/display.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/top/display.c,v
> retrieving revision 1.52
> diff -u -p -r1.52 display.c
> --- usr.bin/top/display.c     15 Mar 2017 04:24:14 -0000      1.52
> +++ usr.bin/top/display.c     15 Dec 2017 00:43:29 -0000
> @@ -57,7 +57,6 @@
>  #include <stdlib.h>
>  #include <string.h>
>  #include <unistd.h>
> -#include <sys/sysctl.h>
>  
>  #include "screen.h"          /* interface to screen package */
>  #include "layout.h"          /* defines for screen position layout */
> @@ -209,22 +208,15 @@ display_init(struct statics * statics)
>  static void
>  format_uptime(char *buf, size_t buflen)
>  {
> -     time_t now, uptime;
> +     time_t uptime;
>       int days, hrs, mins;
> -     int mib[2];
> -     size_t size;
> -     struct timeval boottime;
> +     struct timespec boottime;
>  
> -     now = time(NULL);
>       /*
>        * Print how long system has been up.
> -      * (Found by getting "boottime" from the kernel)
>        */
> -     mib[0] = CTL_KERN;
> -     mib[1] = KERN_BOOTTIME;
> -     size = sizeof(boottime);
> -     if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1) {
> -             uptime = now - boottime.tv_sec;
> +     if (clock_gettime(CLOCK_BOOTTIME, &boottime) != -1) {
> +             uptime = boottime.tv_sec;
>               uptime += 30;
>               days = uptime / (3600 * 24);
>               uptime %= (3600 * 24);
> Index: usr.sbin/snmpd/mib.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/snmpd/mib.c,v
> retrieving revision 1.84
> diff -u -p -r1.84 mib.c
> --- usr.sbin/snmpd/mib.c      1 Jun 2017 14:38:28 -0000       1.84
> +++ usr.sbin/snmpd/mib.c      15 Dec 2017 00:43:29 -0000
> @@ -451,18 +451,13 @@ static struct oid hr_mib[] = {
>  int
>  mib_hrsystemuptime(struct oid *oid, struct ber_oid *o, struct ber_element 
> **elm)
>  {
> -     struct timeval   boottime;
> -     int              mib[] = { CTL_KERN, KERN_BOOTTIME };
> -     time_t           now;
> -     size_t           len;
> +     struct timespec  uptime;
> +     long long        ticks;
>  
> -     (void)time(&now);
> -     len = sizeof(boottime);
> -
> -     if (sysctl(mib, 2, &boottime, &len, NULL, 0) == -1)
> +     if (clock_gettime(CLOCK_BOOTTIME, &uptime) == -1)
>               return (-1);
> -
> -     *elm = ber_add_integer(*elm, (now - boottime.tv_sec) * 100);
> +     ticks = uptime.tv_sec * 100 + uptime.tv_nsec / 10000000;
> +     *elm = ber_add_integer(*elm, ticks);
>       ber_set_header(*elm, BER_CLASS_APPLICATION, SNMP_T_TIMETICKS);
>  
>       return (0);
> 

Reply via email to