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? -- 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);
