> Date: Fri, 5 Jun 2020 01:33:16 +0300 > From: Paul Irofti <p...@irofti.net> > > On Wed, Jun 03, 2020 at 05:13:42PM +0300, Paul Irofti wrote: > > On 2020-05-31 20:46, Mark Kettenis wrote: > > > Forget about all that for a moment. Here is an alternative suggestion: > > > > > > On sparc64 we need to support both tick_timecounter and > > > sys_tick_timecounter. So we need some sort of clockid value to > > > distnguish between those two. I already suggested to use the tc_user > > > field of the timecounter for that. 0 means that a timecounter is not > > > usable in userland, a (small) positive integer means a specific > > > timecounter type. The code in libc will need to know whether a > > > particular timecounter type can be supported. My proposal would be to > > > implement a function*on all architecture* that takes the clockid as > > > an argument and returns a pointer to the function that implements > > > support for that timecounter. On architectures without support, ir > > > when called with a clockid that isn't supported, that function would > > > simply return NULL. > > > > I am sorry, but the more I try to implement this in a sane way, the more > > obvious it is that it is not possible. I would rather have a define sausage > > than something like this. > > > > I will try to think of something else that avoids the defines, but I do not > > think that your proposal is a valid solution. > > OK. I think I found an elegant way around this using the Makefile > system: if usertc.c is not present in the arch/${MACHINE}/gen, then a > stub gen/usertc.c file is built that just sets the function pointer to > NULL. This avoids the need for the define checks in dlfcn/init.c and I > think fixes the rest of the issues discussed around this bit. > > Also included in the diff are a few other fixes and regression tests. > I left the rdtsc and acpihpet example (with no functional acpihpet > support) just to show-case how we can handle multiple clocks on > architectures that have them.
You're still using tk_user unconditionally. If the kernel returns a tk_user value that is larger than what's supported by libc you have an out-of-bounds array access. Also if the machine switches to a timecounter that has tk_user == 0 you have an out-of-bounds array access. If that happens you need to detect this and fall back on the system call. > I could not add support for other architectures as I still do not have > access to my machines. arm64 can be done; I'm waiting with sparc64 until you have worked out how to handle the multiple clocks properly... > Is the Makefile approach good enough? Not sure. Others should judge that. > diff --git lib/libc/arch/amd64/gen/Makefile.inc > lib/libc/arch/amd64/gen/Makefile.inc > index e995309ed71..f6349e2b974 100644 > --- lib/libc/arch/amd64/gen/Makefile.inc > +++ lib/libc/arch/amd64/gen/Makefile.inc > @@ -2,6 +2,7 @@ > > SRCS+= _setjmp.S fabs.S infinity.c ldexp.c modf.S nan.c setjmp.S \ > sigsetjmp.S > -SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c > signbitl.c > +SRCS+= fpclassifyl.c isfinitel.c isinfl.c isnanl.c isnormall.c > signbitl.c \ > + usertc.c > SRCS+= flt_rounds.S fpgetmask.S fpgetround.S fpgetsticky.S fpsetmask.S > \ > fpsetround.S fpsetsticky.S > diff --git lib/libc/arch/amd64/gen/usertc.c lib/libc/arch/amd64/gen/usertc.c > new file mode 100644 > index 00000000000..cec1b484865 > --- /dev/null > +++ lib/libc/arch/amd64/gen/usertc.c > @@ -0,0 +1,46 @@ > +/* $OpenBSD$ */ > +/* > + * Copyright (c) 2020 Paul Irofti <p...@irofti.net> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include <sys/types.h> > +#include <sys/timetc.h> > + > +static uint64_t > +rdtsc() > +{ > + uint32_t hi, lo; > + asm volatile("rdtsc" : "=a"(lo), "=d"(hi)); > + return ((uint64_t)lo)|(((uint64_t)hi)<<32); > +} > + > +static uint64_t > +acpihpet() > +{ > + return rdtsc(); /* JUST TO COMPILE */ > +} > + > +static uint64_t (*get_tc[])(void) = > +{ > + rdtsc, > + acpihpet, > +}; > + > +uint64_t > +tc_get_timecount(struct timekeep *tk) > +{ > + return (*get_tc[tk->tk_user - 1])(); > +} > +uint64_t (*const _tc_get_timecount)(struct timekeep *tk) = tc_get_timecount; > diff --git lib/libc/asr/asr.c lib/libc/asr/asr.c > index cd056c85719..2b25d49f32a 100644 > --- lib/libc/asr/asr.c > +++ lib/libc/asr/asr.c > @@ -196,11 +196,11 @@ poll_intrsafe(struct pollfd *fds, nfds_t nfds, int > timeout) > struct timespec pollstart, pollend, elapsed; > int r; > > - if (clock_gettime(CLOCK_MONOTONIC, &pollstart)) > + if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &pollstart)) > return -1; > > while ((r = poll(fds, 1, timeout)) == -1 && errno == EINTR) { > - if (clock_gettime(CLOCK_MONOTONIC, &pollend)) > + if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &pollend)) > return -1; > timespecsub(&pollend, &pollstart, &elapsed); > timeout -= elapsed.tv_sec * 1000 + elapsed.tv_nsec / 1000000; > @@ -418,7 +418,7 @@ asr_check_reload(struct asr *asr) > asr->a_rtime = 0; > } > > - if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) > + if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts) == -1) > return; > > if ((ts.tv_sec - asr->a_rtime) < RELOAD_DELAY && asr->a_rtime != 0) > diff --git lib/libc/crypt/bcrypt.c lib/libc/crypt/bcrypt.c > index 82de8fa33b7..02fd3013cc1 100644 > --- lib/libc/crypt/bcrypt.c > +++ lib/libc/crypt/bcrypt.c > @@ -248,9 +248,9 @@ _bcrypt_autorounds(void) > char buf[_PASSWORD_LEN]; > int duration; > > - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &before); > + WRAP(clock_gettime)(CLOCK_THREAD_CPUTIME_ID, &before); > bcrypt_newhash("testpassword", r, buf, sizeof(buf)); > - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &after); > + WRAP(clock_gettime)(CLOCK_THREAD_CPUTIME_ID, &after); > > duration = after.tv_sec - before.tv_sec; > duration *= 1000000; > diff --git lib/libc/dlfcn/init.c lib/libc/dlfcn/init.c > index 270f54aada5..19d0a2c3ad6 100644 > --- lib/libc/dlfcn/init.c > +++ lib/libc/dlfcn/init.c > @@ -20,6 +20,7 @@ > > #include <sys/types.h> > #include <sys/syscall.h> > +#include <sys/timetc.h> /* timekeep */ > > #ifndef PIC > #include <sys/mman.h> > @@ -45,8 +46,9 @@ > /* XXX should be in an include file shared with csu */ > char ***_csu_finish(char **_argv, char **_envp, void (*_cleanup)(void)); > > -/* provide definition for this */ > +/* provide definitions for these */ > int _pagesize = 0; > +void *_timekeep = NULL; > > /* > * In dynamicly linked binaries environ and __progname are overriden by > @@ -105,6 +107,10 @@ _libc_preinit(int argc, char **argv, char **envp, > dl_cb_cb *cb) > phnum = aux->au_v; > break; > #endif /* !PIC */ > + case AUX_openbsd_timekeep: > + if (_tc_get_timecount) > + _timekeep = (void *)aux->au_v; > + break; > } > } > > diff --git lib/libc/gen/Makefile.inc lib/libc/gen/Makefile.inc > index cf36ead40e9..da52d9fbb13 100644 > --- lib/libc/gen/Makefile.inc > +++ lib/libc/gen/Makefile.inc > @@ -27,6 +27,10 @@ SRCS+= alarm.c assert.c auth_subr.c authenticate.c \ > utime.c valloc.c vis.c wait.c wait3.c waitpid.c warn.c \ > warnc.c warnx.c vwarn.c vwarnc.c vwarnx.c verr.c verrc.c verrx.c > > +.if !exists (${LIBCSRCDIR}/arch/${MACHINE_CPU}/gen/usertc.c) > +SRCS+= usertc.c > +.endif > + > # machine-dependent gen sources > # m-d Makefile.inc must include sources for: > # _setjmp() fabs() frexp() infinity ldexp() modf() __nan > diff --git lib/libc/gen/auth_subr.c lib/libc/gen/auth_subr.c > index 1286a96fe40..32f86eda50f 100644 > --- lib/libc/gen/auth_subr.c > +++ lib/libc/gen/auth_subr.c > @@ -752,7 +752,7 @@ auth_check_expire(auth_session_t *as) > > if (as->pwd && (quad_t)as->pwd->pw_expire != 0) { > if (as->now.tv_sec == 0) > - gettimeofday(&as->now, NULL); > + WRAP(gettimeofday)(&as->now, NULL); > if ((quad_t)as->now.tv_sec >= (quad_t)as->pwd->pw_expire) { > as->state &= ~AUTH_ALLOW; > as->state |= AUTH_EXPIRED; > @@ -779,7 +779,7 @@ auth_check_change(auth_session_t *as) > > if (as->pwd && (quad_t)as->pwd->pw_change) { > if (as->now.tv_sec == 0) > - gettimeofday(&as->now, NULL); > + WRAP(gettimeofday)(&as->now, NULL); > if (as->now.tv_sec >= (quad_t)as->pwd->pw_change) { > as->state &= ~AUTH_ALLOW; > as->state |= AUTH_PWEXPIRED; > diff --git lib/libc/gen/time.c lib/libc/gen/time.c > index 3bbd0d733d1..b3ce9a800f1 100644 > --- lib/libc/gen/time.c > +++ lib/libc/gen/time.c > @@ -36,7 +36,7 @@ time(time_t *t) > { > struct timeval tt; > > - if (gettimeofday(&tt, NULL) == -1) > + if (WRAP(gettimeofday)(&tt, NULL) == -1) > return (-1); > if (t) > *t = (time_t)tt.tv_sec; > diff --git lib/libc/gen/times.c lib/libc/gen/times.c > index 02e4dd44b5c..36841810d1b 100644 > --- lib/libc/gen/times.c > +++ lib/libc/gen/times.c > @@ -52,7 +52,7 @@ times(struct tms *tp) > return ((clock_t)-1); > tp->tms_cutime = CONVTCK(ru.ru_utime); > tp->tms_cstime = CONVTCK(ru.ru_stime); > - if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) > + if (WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts) == -1) > return ((clock_t)-1); > return (ts.tv_sec * CLK_TCK + ts.tv_nsec / (1000000000 / CLK_TCK)); > } > diff --git lib/libc/gen/timespec_get.c lib/libc/gen/timespec_get.c > index 520a5954025..845cbe80356 100644 > --- lib/libc/gen/timespec_get.c > +++ lib/libc/gen/timespec_get.c > @@ -37,7 +37,7 @@ timespec_get(struct timespec *ts, int base) > { > switch (base) { > case TIME_UTC: > - if (clock_gettime(CLOCK_REALTIME, ts) == -1) > + if (WRAP(clock_gettime)(CLOCK_REALTIME, ts) == -1) > return 0; > break; > default: > diff --git lib/libc/gen/usertc.c lib/libc/gen/usertc.c > new file mode 100644 > index 00000000000..43fa1728361 > --- /dev/null > +++ lib/libc/gen/usertc.c > @@ -0,0 +1,24 @@ > +/* $OpenBSD$ */ > +/* > + * Copyright (c) 2020 Paul Irofti <p...@irofti.net> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include <sys/types.h> > +#include <sys/timetc.h> > + > +/* > + * Stub. Add implementation in arch/${MACHINE_CPU}/gen/usertc.c. > + */ > +uint64_t (*const _tc_get_timecount)(struct timekeep *tk) = NULL; > diff --git lib/libc/hidden/sys/time.h lib/libc/hidden/sys/time.h > index ed112320fa2..df717021cab 100644 > --- lib/libc/hidden/sys/time.h > +++ lib/libc/hidden/sys/time.h > @@ -24,7 +24,7 @@ PROTO_NORMAL(adjfreq); > PROTO_NORMAL(adjtime); > PROTO_NORMAL(futimes); > PROTO_NORMAL(getitimer); > -PROTO_NORMAL(gettimeofday); > +PROTO_WRAP(gettimeofday); > PROTO_NORMAL(setitimer); > PROTO_NORMAL(settimeofday); > PROTO_NORMAL(utimes); > diff --git lib/libc/hidden/sys/timetc.h lib/libc/hidden/sys/timetc.h > new file mode 100644 > index 00000000000..b0c982ebe57 > --- /dev/null > +++ lib/libc/hidden/sys/timetc.h > @@ -0,0 +1,38 @@ > +/* $OpenBSD$ */ > +/* > + * Copyright (c) 2020 Paul Irofti <p...@irofti.net> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#ifndef _LIBC_SYS_TIMETC_H_ > +#define _LIBC_SYS_TIMETC_H_ > + > +#define _LIBC > +#include <sys/types.h> > +#include <sys/time.h> > + > +#include_next <sys/timetc.h> > + > +__BEGIN_HIDDEN_DECLS > +extern void *_timekeep; > + > +extern uint64_t (*const _tc_get_timecount)(struct timekeep *tk); > + > +void _microtime(struct timeval *tvp, struct timekeep *tk); > +void _nanotime(struct timespec *tsp, struct timekeep *tk); > +void _nanoruntime(struct timespec *ts, struct timekeep *tk); > +void _nanouptime(struct timespec *tsp, struct timekeep *tk); > +__END_HIDDEN_DECLS > + > +#endif /* !_LIBC_SYS_TIMETC_H_ */ > diff --git lib/libc/hidden/time.h lib/libc/hidden/time.h > index 18c49f8fcb9..d8e1e0caf64 100644 > --- lib/libc/hidden/time.h > +++ lib/libc/hidden/time.h > @@ -29,7 +29,7 @@ PROTO_NORMAL(asctime_r); > PROTO_STD_DEPRECATED(clock); > PROTO_DEPRECATED(clock_getcpuclockid); > PROTO_NORMAL(clock_getres); > -PROTO_NORMAL(clock_gettime); > +PROTO_WRAP(clock_gettime); > PROTO_NORMAL(clock_settime); > PROTO_STD_DEPRECATED(ctime); > PROTO_DEPRECATED(ctime_r); > diff --git lib/libc/net/res_random.c lib/libc/net/res_random.c > index 763e420bb88..9babb28470a 100644 > --- lib/libc/net/res_random.c > +++ lib/libc/net/res_random.c > @@ -219,7 +219,7 @@ res_initid(void) > if (ru_prf != NULL) > arc4random_buf(ru_prf, sizeof(*ru_prf)); > > - clock_gettime(CLOCK_MONOTONIC, &ts); > + WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts); > ru_reseed = ts.tv_sec + RU_OUT; > ru_msb = ru_msb == 0x8000 ? 0 : 0x8000; > } > @@ -232,7 +232,7 @@ __res_randomid(void) > u_int r; > static void *randomid_mutex; > > - clock_gettime(CLOCK_MONOTONIC, &ts); > + WRAP(clock_gettime)(CLOCK_MONOTONIC, &ts); > pid = getpid(); > > _MUTEX_LOCK(&randomid_mutex); > diff --git lib/libc/rpc/auth_unix.c lib/libc/rpc/auth_unix.c > index 402d98cede4..917a6d42b8a 100644 > --- lib/libc/rpc/auth_unix.c > +++ lib/libc/rpc/auth_unix.c > @@ -121,7 +121,7 @@ authunix_create(char *machname, int uid, int gid, int > len, int *aup_gids) > /* > * fill in param struct from the given params > */ > - (void)gettimeofday(&now, NULL); > + (void)WRAP(gettimeofday)(&now, NULL); > aup.aup_time = now.tv_sec; > aup.aup_machname = machname; > aup.aup_uid = uid; > @@ -274,7 +274,7 @@ authunix_refresh(AUTH *auth) > goto done; > > /* update the time and serialize in place */ > - (void)gettimeofday(&now, NULL); > + (void)WRAP(gettimeofday)(&now, NULL); > aup.aup_time = now.tv_sec; > xdrs.x_op = XDR_ENCODE; > XDR_SETPOS(&xdrs, 0); > diff --git lib/libc/rpc/clnt_tcp.c lib/libc/rpc/clnt_tcp.c > index 8e6ef515b0e..927b4bf2028 100644 > --- lib/libc/rpc/clnt_tcp.c > +++ lib/libc/rpc/clnt_tcp.c > @@ -393,12 +393,12 @@ readtcp(struct ct_data *ct, caddr_t buf, int len) > pfd[0].events = POLLIN; > TIMEVAL_TO_TIMESPEC(&ct->ct_wait, &wait); > delta = wait; > - clock_gettime(CLOCK_MONOTONIC, &start); > + WRAP(clock_gettime)(CLOCK_MONOTONIC, &start); > for (;;) { > r = ppoll(pfd, 1, &delta, NULL); > save_errno = errno; > > - clock_gettime(CLOCK_MONOTONIC, &after); > + WRAP(clock_gettime)(CLOCK_MONOTONIC, &after); > timespecsub(&start, &after, &duration); > timespecsub(&wait, &duration, &delta); > if (delta.tv_sec < 0 || !timespecisset(&delta)) > diff --git lib/libc/rpc/clnt_udp.c lib/libc/rpc/clnt_udp.c > index 68d01674410..92e1d5c350d 100644 > --- lib/libc/rpc/clnt_udp.c > +++ lib/libc/rpc/clnt_udp.c > @@ -265,7 +265,7 @@ send_again: > reply_msg.acpted_rply.ar_results.where = resultsp; > reply_msg.acpted_rply.ar_results.proc = xresults; > > - clock_gettime(CLOCK_MONOTONIC, &start); > + WRAP(clock_gettime)(CLOCK_MONOTONIC, &start); > for (;;) { > switch (ppoll(pfd, 1, &wait, NULL)) { > case 0: > @@ -283,7 +283,7 @@ send_again: > /* FALLTHROUGH */ > case -1: > if (errno == EINTR) { > - clock_gettime(CLOCK_MONOTONIC, &after); > + WRAP(clock_gettime)(CLOCK_MONOTONIC, &after); > timespecsub(&after, &start, &duration); > timespecadd(&time_waited, &duration, > &time_waited); > if (timespeccmp(&time_waited, &timeout, <)) > diff --git lib/libc/rpc/svc_tcp.c lib/libc/rpc/svc_tcp.c > index f9d7a70938f..6c99db84359 100644 > --- lib/libc/rpc/svc_tcp.c > +++ lib/libc/rpc/svc_tcp.c > @@ -342,7 +342,7 @@ readtcp(SVCXPRT *xprt, caddr_t buf, int len) > * A timeout is fatal for the connection. > */ > delta = wait_per_try; > - clock_gettime(CLOCK_MONOTONIC, &start); > + WRAP(clock_gettime)(CLOCK_MONOTONIC, &start); > pfd[0].fd = sock; > pfd[0].events = POLLIN; > do { > @@ -351,7 +351,7 @@ readtcp(SVCXPRT *xprt, caddr_t buf, int len) > case -1: > if (errno != EINTR) > goto fatal_err; > - clock_gettime(CLOCK_MONOTONIC, &after); > + WRAP(clock_gettime)(CLOCK_MONOTONIC, &after); > timespecsub(&after, &start, &duration); > timespecsub(&wait_per_try, &duration, &delta); > if (delta.tv_sec < 0 || !timespecisset(&delta)) > diff --git lib/libc/sys/Makefile.inc lib/libc/sys/Makefile.inc > index 34769576ced..d57418d81bf 100644 > --- lib/libc/sys/Makefile.inc > +++ lib/libc/sys/Makefile.inc > @@ -12,7 +12,8 @@ SRCS+= Ovfork.S brk.S ${CERROR} \ > > # glue to offer userland wrappers for some syscalls > SRCS+= posix_madvise.c pthread_sigmask.c \ > - w_fork.c w_sigaction.c w_sigprocmask.c w_sigsuspend.c w_vfork.c > + w_fork.c w_sigaction.c w_sigprocmask.c w_sigsuspend.c w_vfork.c \ > + w_clock_gettime.c w_gettimeofday.c microtime.c > > # glue for compat with old syscall interfaces. > SRCS+= ftruncate.c lseek.c mquery.c mmap.c ptrace.c semctl.c > truncate.c \ > @@ -43,7 +44,7 @@ SRCS+= ${CANCEL:%=w_%.c} w_pread.c w_preadv.c > w_pwrite.c w_pwritev.c > ASM= __semctl.o __syscall.o __thrsigdivert.o \ > access.o acct.o adjfreq.o adjtime.o \ > bind.o chdir.o chflags.o chflagsat.o chmod.o chown.o chroot.o \ > - clock_getres.o clock_gettime.o clock_settime.o \ > + clock_getres.o clock_settime.o \ > dup.o dup2.o dup3.o \ > execve.o \ > faccessat.o fchdir.o fchflags.o fchmod.o fchmodat.o fchown.o \ > @@ -54,7 +55,7 @@ ASM= __semctl.o __syscall.o __thrsigdivert.o \ > getgroups.o getitimer.o getpeername.o getpgid.o \ > getpriority.o getresgid.o getresuid.o \ > getrlimit.o getrusage.o getsid.o getsockname.o \ > - getsockopt.o gettimeofday.o ioctl.o \ > + getsockopt.o ioctl.o \ > kevent.o kill.o kqueue.o ktrace.o lchown.o \ > link.o linkat.o listen.o lstat.o madvise.o \ > minherit.o mkdir.o mkdirat.o mkfifo.o mkfifoat.o \ > @@ -109,7 +110,8 @@ PPSEUDO_NOERR=${PSEUDO_NOERR:.o=.po} > SPSEUDO_NOERR=${PSEUDO_NOERR:.o=.so} > DPSEUDO_NOERR=${PSEUDO_NOERR:.o=.do} > > -HIDDEN= ___realpath.o ___getcwd.o fork.o sigaction.o _ptrace.o ${CANCEL:=.o} > +HIDDEN= ___realpath.o ___getcwd.o fork.o sigaction.o _ptrace.o ${CANCEL:=.o} > \ > + clock_gettime.o gettimeofday.o > PHIDDEN=${HIDDEN:.o=.po} > SHIDDEN=${HIDDEN:.o=.so} > DHIDDEN=${HIDDEN:.o=.do} > diff --git lib/libc/sys/microtime.c lib/libc/sys/microtime.c > new file mode 100644 > index 00000000000..6eb3cd40d28 > --- /dev/null > +++ lib/libc/sys/microtime.c > @@ -0,0 +1,157 @@ > +/* $OpenBSD$ */ > +/* > + * Copyright (c) 2000 Poul-Henning Kamp <p...@freebsd.org> > + * Copyright (c) 2020 Paul Irofti <p...@irofti.net> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include <sys/types.h> > +#include <sys/atomic.h> > +#include <sys/timetc.h> > + > +#include <time.h> > + > +/* > + * Return the difference between the timehands' counter value now and what > + * was when we copied it to the timehands' offset_count. > + */ > +static inline u_int > +tc_delta(struct timekeep *tk) > +{ > + return ((_tc_get_timecount(tk) - tk->tk_offset_count) & > + tk->tk_counter_mask); > +} > + > +static inline void > +bintimeaddfrac(const struct bintime *bt, uint64_t x, struct bintime *ct) > +{ > + ct->sec = bt->sec; > + if (bt->frac > bt->frac + x) > + ct->sec++; > + ct->frac = bt->frac + x; > +} > + > +static inline void > +BINTIME_TO_TIMESPEC(const struct bintime *bt, struct timespec *ts) > +{ > + ts->tv_sec = bt->sec; > + ts->tv_nsec = (long)(((uint64_t)1000000000 * (uint32_t)(bt->frac >> > 32)) >> 32); > +} > + > +static inline void > +BINTIME_TO_TIMEVAL(const struct bintime *bt, struct timeval *tv) > +{ > + tv->tv_sec = bt->sec; > + tv->tv_usec = (long)(((uint64_t)1000000 * (uint32_t)(bt->frac >> 32)) > >> 32); > +} > + > +static void > +binuptime(struct bintime *bt, struct timekeep *tk) > +{ > + u_int gen; > + > + do { > + gen = tk->tk_generation; > + membar_consumer(); > + *bt = tk->tk_offset; > + bintimeaddfrac(bt, tk->tk_scale * tc_delta(tk), bt); > + membar_consumer(); > + } while (gen == 0 || gen != tk->tk_generation); > +} > + > +static inline void > +bintimeadd(const struct bintime *bt, const struct bintime *ct, > + struct bintime *dt) > +{ > + dt->sec = bt->sec + ct->sec; > + if (bt->frac > bt->frac + ct->frac) > + dt->sec++; > + dt->frac = bt->frac + ct->frac; > +} > + > +static inline void > +bintimesub(const struct bintime *bt, const struct bintime *ct, > + struct bintime *dt) > +{ > + dt->sec = bt->sec - ct->sec; > + if (bt->frac < bt->frac - ct->frac) > + dt->sec--; > + dt->frac = bt->frac - ct->frac; > +} > + > +static void > +binruntime(struct bintime *bt, struct timekeep *tk) > +{ > + u_int gen; > + > + do { > + gen = tk->tk_generation; > + membar_consumer(); > + bintimeaddfrac(&tk->tk_offset, tk->tk_scale * tc_delta(tk), bt); > + bintimesub(bt, &tk->tk_naptime, bt); > + membar_consumer(); > + } while (gen == 0 || gen != tk->tk_generation); > +} > + > +static void > +bintime(struct bintime *bt, struct timekeep *tk) > +{ > + u_int gen; > + > + do { > + gen = tk->tk_generation; > + membar_consumer(); > + *bt = tk->tk_offset; > + bintimeaddfrac(bt, tk->tk_scale * tc_delta(tk), bt); > + bintimeadd(bt, &tk->tk_boottime, bt); > + membar_consumer(); > + } while (gen == 0 || gen != tk->tk_generation); > +} > + > +void > +_microtime(struct timeval *tvp, struct timekeep *tk) > +{ > + struct bintime bt; > + > + bintime(&bt, tk); > + BINTIME_TO_TIMEVAL(&bt, tvp); > +} > + > +void > +_nanotime(struct timespec *tsp, struct timekeep *tk) > +{ > + struct bintime bt; > + > + bintime(&bt, tk); > + BINTIME_TO_TIMESPEC(&bt, tsp); > +} > + > +void > +_nanoruntime(struct timespec *ts, struct timekeep *tk) > +{ > + struct bintime bt; > + > + binruntime(&bt, tk); > + BINTIME_TO_TIMESPEC(&bt, ts); > +} > + > + > +void > +_nanouptime(struct timespec *tsp, struct timekeep *tk) > +{ > + struct bintime bt; > + > + binuptime(&bt, tk); > + BINTIME_TO_TIMESPEC(&bt, tsp); > +} > diff --git lib/libc/sys/w_clock_gettime.c lib/libc/sys/w_clock_gettime.c > new file mode 100644 > index 00000000000..ff72c9fb64d > --- /dev/null > +++ lib/libc/sys/w_clock_gettime.c > @@ -0,0 +1,46 @@ > +/* $OpenBSD$ */ > +/* > + * Copyright (c) 2020 Paul Irofti <p...@irofti.net> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include <sys/timetc.h> > + > +#include <time.h> > + > +int > +WRAP(clock_gettime)(clockid_t clock_id, struct timespec *tp) > +{ > + struct timekeep *timekeep = _timekeep; > + > + if (timekeep == NULL || timekeep->tk_user == 0) > + return clock_gettime(clock_id, tp); > + > + switch (clock_id) { > + case CLOCK_REALTIME: > + _nanotime(tp, timekeep); > + break; > + case CLOCK_UPTIME: > + _nanoruntime(tp, timekeep); > + break; > + case CLOCK_MONOTONIC: > + case CLOCK_BOOTTIME: > + _nanouptime(tp, timekeep); > + break; > + default: > + return clock_gettime(clock_id, tp); > + } > + return 0; > +} > +DEF_WRAP(clock_gettime); > diff --git lib/libc/sys/w_gettimeofday.c lib/libc/sys/w_gettimeofday.c > new file mode 100644 > index 00000000000..0b198190485 > --- /dev/null > +++ lib/libc/sys/w_gettimeofday.c > @@ -0,0 +1,37 @@ > +/* $OpenBSD$ */ > +/* > + * Copyright (c) 2020 Robert Nagy <rob...@openbsd.org> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include <sys/timetc.h> > + > +int > +WRAP(gettimeofday)(struct timeval *tp, struct timezone *tzp) > +{ > + struct timekeep *timekeep = _timekeep; > + static struct timezone zerotz = { 0, 0 }; > + > + if (timekeep == NULL || timekeep->tk_user == 0) > + return gettimeofday(tp, tzp); > + > + if (tp) > + _microtime(tp, timekeep); > + > + if (tzp) > + tzp = &zerotz; > + > + return 0; > +} > +DEF_WRAP(gettimeofday); > diff --git lib/libc/thread/synch.h lib/libc/thread/synch.h > index 788890add89..df2239438d2 100644 > --- lib/libc/thread/synch.h > +++ lib/libc/thread/synch.h > @@ -33,7 +33,7 @@ _twait(volatile uint32_t *p, int val, clockid_t clockid, > const struct timespec * > if (abs == NULL) > return futex(p, FUTEX_WAIT_PRIVATE, val, NULL, NULL); > > - if (abs->tv_nsec >= 1000000000 || clock_gettime(clockid, &rel)) > + if (abs->tv_nsec >= 1000000000 || WRAP(clock_gettime)(clockid, &rel)) > return (EINVAL); > > rel.tv_sec = abs->tv_sec - rel.tv_sec; > diff --git regress/lib/libc/timekeep/Makefile > regress/lib/libc/timekeep/Makefile > new file mode 100644 > index 00000000000..a7f3080290d > --- /dev/null > +++ regress/lib/libc/timekeep/Makefile > @@ -0,0 +1,5 @@ > +# $OpenBSD$ > + > +PROGS= test_clock_gettime test_time_skew test_gettimeofday > + > +.include <bsd.regress.mk> > diff --git regress/lib/libc/timekeep/test_clock_gettime.c > regress/lib/libc/timekeep/test_clock_gettime.c > new file mode 100644 > index 00000000000..859ec368215 > --- /dev/null > +++ regress/lib/libc/timekeep/test_clock_gettime.c > @@ -0,0 +1,43 @@ > +/* $OpenBSD$ */ > +/* > + * Copyright (c) 2020 Paul Irofti <p...@irofti.net> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include <assert.h> > +#include <time.h> > + > +#define ASSERT_EQ(a, b) assert((a) == (b)) > + > +void > +check() > +{ > + struct timespec tp = {0}; > + > + ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &tp)); > + ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp)); > + ASSERT_EQ(0, clock_gettime(CLOCK_BOOTTIME, &tp)); > + ASSERT_EQ(0, clock_gettime(CLOCK_UPTIME, &tp)); > + > + > + ASSERT_EQ(0, clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp)); > + ASSERT_EQ(0, clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp)); > + > +} > + > +int main() > +{ > + check(); > + return 0; > +} > diff --git regress/lib/libc/timekeep/test_gettimeofday.c > regress/lib/libc/timekeep/test_gettimeofday.c > new file mode 100644 > index 00000000000..ea90a1be7e0 > --- /dev/null > +++ regress/lib/libc/timekeep/test_gettimeofday.c > @@ -0,0 +1,37 @@ > +/* $OpenBSD$ */ > +/* > + * Copyright (c) 2020 Paul Irofti <p...@irofti.net> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include <assert.h> > +#include <sys/time.h> > + > +#define ASSERT_EQ(a, b) assert((a) == (b)) > + > +void > +check() > +{ > + struct timeval tv = {0}; > + struct timezone tzp; > + > + ASSERT_EQ(0, gettimeofday(&tv, NULL)); > + ASSERT_EQ(0, gettimeofday(&tv, &tzp)); > +} > + > +int main() > +{ > + check(); > + return 0; > +} > diff --git regress/lib/libc/timekeep/test_time_skew.c > regress/lib/libc/timekeep/test_time_skew.c > new file mode 100644 > index 00000000000..dfa9481c091 > --- /dev/null > +++ regress/lib/libc/timekeep/test_time_skew.c > @@ -0,0 +1,55 @@ > +/* $OpenBSD$ */ > +/* > + * Copyright (c) 2020 Paul Irofti <p...@irofti.net> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include <sys/time.h> > + > +#include <assert.h> > +#include <time.h> > +#include <stdlib.h> > +#include <stdio.h> > + > +#define ASSERT_EQ(a, b) assert((a) == (b)) > +#define ASSERT_NE(a, b) assert((a) != (b)) > + > +void > +check() > +{ > + struct timespec tp1, tp2, tout; > + > + tout.tv_sec = 0; > + tout.tv_nsec = 100000; > + > + ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp1)); > + > + nanosleep(&tout, NULL); > + > + ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &tp2)); > + > + /* tp1 should never be larger than tp2 */ > + ASSERT_NE(1, timespeccmp(&tp1, &tp2, >)); > +} > + > +int > +main(void) > +{ > + int i; > + > + for (i = 0; i < 1000; i++) > + check(); > + > + return 0; > +} > diff --git sys/arch/alpha/alpha/clock.c sys/arch/alpha/alpha/clock.c > index 3f5f2c5b42b..6eaf8b107c6 100644 > --- sys/arch/alpha/alpha/clock.c > +++ sys/arch/alpha/alpha/clock.c > @@ -64,7 +64,7 @@ int clk_irq = 0; > > u_int rpcc_get_timecount(struct timecounter *); > struct timecounter rpcc_timecounter = { > - rpcc_get_timecount, NULL, ~0u, 0, "rpcc", 0, NULL > + rpcc_get_timecount, NULL, ~0u, 0, "rpcc", 0, NULL, 0 > }; > > extern todr_chip_handle_t todr_handle; > diff --git sys/arch/amd64/amd64/tsc.c sys/arch/amd64/amd64/tsc.c > index 7a1dcb4ad75..3db93d88dec 100644 > --- sys/arch/amd64/amd64/tsc.c > +++ sys/arch/amd64/amd64/tsc.c > @@ -50,7 +50,7 @@ extern u_int32_t lapic_per_second; > #endif > > struct timecounter tsc_timecounter = { > - tsc_get_timecount, NULL, ~0u, 0, "tsc", -1000, NULL > + tsc_get_timecount, NULL, ~0u, 0, "tsc", -1000, NULL, 1 > }; > > uint64_t > diff --git sys/arch/amd64/isa/clock.c sys/arch/amd64/isa/clock.c > index 613f7ee0e0f..00da0c6a8d0 100644 > --- sys/arch/amd64/isa/clock.c > +++ sys/arch/amd64/isa/clock.c > @@ -116,7 +116,7 @@ u_int i8254_get_timecount(struct timecounter *tc); > u_int i8254_simple_get_timecount(struct timecounter *tc); > > static struct timecounter i8254_timecounter = { > - i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL > + i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL, 0 > }; > > int clockintr(void *); > diff --git sys/arch/arm64/dev/agtimer.c sys/arch/arm64/dev/agtimer.c > index 29394141ad5..6b7c6db862f 100644 > --- sys/arch/arm64/dev/agtimer.c > +++ sys/arch/arm64/dev/agtimer.c > @@ -43,7 +43,7 @@ int32_t agtimer_frequency = TIMER_FREQUENCY; > u_int agtimer_get_timecount(struct timecounter *); > > static struct timecounter agtimer_timecounter = { > - agtimer_get_timecount, NULL, 0x7fffffff, 0, "agtimer", 0, NULL > + agtimer_get_timecount, NULL, 0x7fffffff, 0, "agtimer", 0, NULL, 0 > }; > > struct agtimer_pcpu_softc { > diff --git sys/arch/armv7/omap/gptimer.c sys/arch/armv7/omap/gptimer.c > index 7605845d5e2..061542d532f 100644 > --- sys/arch/armv7/omap/gptimer.c > +++ sys/arch/armv7/omap/gptimer.c > @@ -117,7 +117,7 @@ int gptimer_irq = 0; > u_int gptimer_get_timecount(struct timecounter *); > > static struct timecounter gptimer_timecounter = { > - gptimer_get_timecount, NULL, 0x7fffffff, 0, "gptimer", 0, NULL > + gptimer_get_timecount, NULL, 0x7fffffff, 0, "gptimer", 0, NULL, 0 > }; > > volatile u_int32_t nexttickevent; > diff --git sys/arch/armv7/sunxi/sxitimer.c sys/arch/armv7/sunxi/sxitimer.c > index 14a243c78d0..41028f9a602 100644 > --- sys/arch/armv7/sunxi/sxitimer.c > +++ sys/arch/armv7/sunxi/sxitimer.c > @@ -89,7 +89,7 @@ void sxitimer_delay(u_int); > u_int sxitimer_get_timecount(struct timecounter *); > > static struct timecounter sxitimer_timecounter = { > - sxitimer_get_timecount, NULL, 0xffffffff, 0, "sxitimer", 0, NULL > + sxitimer_get_timecount, NULL, 0xffffffff, 0, "sxitimer", 0, NULL, 0 > }; > > bus_space_tag_t sxitimer_iot; > diff --git sys/arch/hppa/dev/clock.c sys/arch/hppa/dev/clock.c > index 4c594ab5ec7..8cce6c3a893 100644 > --- sys/arch/hppa/dev/clock.c > +++ sys/arch/hppa/dev/clock.c > @@ -47,7 +47,7 @@ int cpu_hardclock(void *); > u_int itmr_get_timecount(struct timecounter *); > > struct timecounter itmr_timecounter = { > - itmr_get_timecount, NULL, 0xffffffff, 0, "itmr", 0, NULL > + itmr_get_timecount, NULL, 0xffffffff, 0, "itmr", 0, NULL, 0 > }; > > extern todr_chip_handle_t todr_handle; > diff --git sys/arch/i386/isa/clock.c sys/arch/i386/isa/clock.c > index 09a6db983f2..dd74bd425ad 100644 > --- sys/arch/i386/isa/clock.c > +++ sys/arch/i386/isa/clock.c > @@ -129,7 +129,7 @@ u_int i8254_get_timecount(struct timecounter *tc); > u_int i8254_simple_get_timecount(struct timecounter *tc); > > static struct timecounter i8254_timecounter = { > - i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL > + i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL, 0 > }; > struct mutex timer_mutex = MUTEX_INITIALIZER(IPL_HIGH); > u_long rtclock_tval; > diff --git sys/arch/i386/pci/geodesc.c sys/arch/i386/pci/geodesc.c > index 9d9f061eef9..bb8e4c7f9ae 100644 > --- sys/arch/i386/pci/geodesc.c > +++ sys/arch/i386/pci/geodesc.c > @@ -65,7 +65,9 @@ struct timecounter geodesc_timecounter = { > 0xffffffff, /* counter_mask */ > 27000000, /* frequency */ > "GEOTSC", /* name */ > - 2000 /* quality */ > + 2000, /* quality */ > + NULL, /* private bits */ > + 0 /* expose to user */ > }; > > int > diff --git sys/arch/i386/pci/gscpm.c sys/arch/i386/pci/gscpm.c > index 8b8aa4ac430..a6f324e66f3 100644 > --- sys/arch/i386/pci/gscpm.c > +++ sys/arch/i386/pci/gscpm.c > @@ -55,7 +55,9 @@ struct timecounter gscpm_timecounter = { > 0xffffff, /* counter_mask */ > 3579545, /* frequency */ > "GSCPM", /* name */ > - 1000 /* quality */ > + 1000, /* quality */ > + NULL, /* private bits */ > + 0 /* expose to user */ > }; > > struct cfattach gscpm_ca = { > diff --git sys/arch/i386/pci/ichpcib.c sys/arch/i386/pci/ichpcib.c > index 6abf1627de2..629a86a14ff 100644 > --- sys/arch/i386/pci/ichpcib.c > +++ sys/arch/i386/pci/ichpcib.c > @@ -63,7 +63,9 @@ struct timecounter ichpcib_timecounter = { > 0xffffff, /* counter_mask */ > 3579545, /* frequency */ > "ICHPM", /* name */ > - 1000 /* quality */ > + 1000, /* quality */ > + NULL, /* private bits */ > + 0 /* expose to user */ > }; > > struct cfattach ichpcib_ca = { > diff --git sys/arch/loongson/loongson/generic3a_machdep.c > sys/arch/loongson/loongson/generic3a_machdep.c > index ac3f1db6ccd..53489b07549 100644 > --- sys/arch/loongson/loongson/generic3a_machdep.c > +++ sys/arch/loongson/loongson/generic3a_machdep.c > @@ -98,7 +98,9 @@ struct timecounter rs780e_timecounter = { > .tc_counter_mask = 0xffffffffu, /* truncated to 32 bits */ > .tc_frequency = HPET_FREQ, > .tc_name = "hpet", > - .tc_quality = 100 > + .tc_quality = 100, > + .tc_priv = NULL, > + .tc_user = 0, > }; > > /* Firmware entry points */ > diff --git sys/arch/luna88k/luna88k/clock.c sys/arch/luna88k/luna88k/clock.c > index a04120987e0..6580a4a46bf 100644 > --- sys/arch/luna88k/luna88k/clock.c > +++ sys/arch/luna88k/luna88k/clock.c > @@ -112,7 +112,9 @@ struct timecounter clock_tc = { > .tc_counter_mask = 0xffffffff, > .tc_frequency = 0, /* will be filled in */ > .tc_name = "clock", > - .tc_quality = 0 > + .tc_quality = 0, > + .tc_priv = NULL, > + .tc_user = 0, > }; > > /* > diff --git sys/arch/macppc/macppc/clock.c sys/arch/macppc/macppc/clock.c > index 4a44a92cfc0..8c3ad620be8 100644 > --- sys/arch/macppc/macppc/clock.c > +++ sys/arch/macppc/macppc/clock.c > @@ -57,7 +57,7 @@ u_int32_t ns_per_tick = 320; > static int32_t ticks_per_intr; > > static struct timecounter tb_timecounter = { > - tb_get_timecount, NULL, 0x7fffffff, 0, "tb", 0, NULL > + tb_get_timecount, NULL, 0x7fffffff, 0, "tb", 0, NULL, 0 > }; > > /* calibrate the timecounter frequency for the listed models */ > diff --git sys/arch/mips64/mips64/mips64_machdep.c > sys/arch/mips64/mips64/mips64_machdep.c > index d4a42ed5acc..5c4dbadb5bb 100644 > --- sys/arch/mips64/mips64/mips64_machdep.c > +++ sys/arch/mips64/mips64/mips64_machdep.c > @@ -327,7 +327,9 @@ struct timecounter cp0_timecounter = { > 0xffffffff, /* counter_mask */ > 0, /* frequency */ > "CP0", /* name */ > - 0 /* quality */ > + 0, /* quality */ > + NULL, /* private bits */ > + 0, /* expose to user */ > }; > > u_int > diff --git sys/arch/octeon/octeon/machdep.c sys/arch/octeon/octeon/machdep.c > index 1387af284ca..2b22a9e942c 100644 > --- sys/arch/octeon/octeon/machdep.c > +++ sys/arch/octeon/octeon/machdep.c > @@ -151,8 +151,9 @@ struct timecounter ioclock_timecounter = { > .tc_name = "ioclock", > .tc_quality = 0, /* ioclock can be overridden > * by cp0 counter */ > - .tc_priv = 0 /* clock register, > + .tc_priv = 0, /* clock register, > * determined at runtime */ > + .tc_user = 0, /* expose to user */ > }; > > static int > diff --git sys/arch/sgi/sgi/ip27_machdep.c sys/arch/sgi/sgi/ip27_machdep.c > index ba7fa558b96..2a2cc144242 100644 > --- sys/arch/sgi/sgi/ip27_machdep.c > +++ sys/arch/sgi/sgi/ip27_machdep.c > @@ -111,7 +111,9 @@ struct timecounter ip27_hub_timecounter = { > .tc_counter_mask = 0xffffffff, /* truncated to 32 bits. */ > .tc_frequency = 1250000, > .tc_name = "hubrt", > - .tc_quality = 100 > + .tc_quality = 100, > + .tc_priv = 0, > + .tc_user = 0, > }; > > volatile uint64_t ip27_spinup_a0; > diff --git sys/arch/sgi/xbow/xheart.c sys/arch/sgi/xbow/xheart.c > index 56b29915c70..827775512ac 100644 > --- sys/arch/sgi/xbow/xheart.c > +++ sys/arch/sgi/xbow/xheart.c > @@ -83,7 +83,9 @@ struct timecounter xheart_timecounter = { > .tc_counter_mask = 0xffffffff, /* truncate 52-bit counter to 32-bit */ > .tc_frequency = 12500000, > .tc_name = "heart", > - .tc_quality = 100 > + .tc_quality = 100, > + .tc_priv = NULL, > + .tc_user = 0, > }; > > extern uint32_t ip30_lights_frob(uint32_t, struct trapframe *); > diff --git sys/arch/sparc64/dev/psycho.c sys/arch/sparc64/dev/psycho.c > index e24f804dff6..1a7a1afa8c2 100644 > --- sys/arch/sparc64/dev/psycho.c > +++ sys/arch/sparc64/dev/psycho.c > @@ -127,7 +127,7 @@ extern struct sparc_pci_chipset _sparc_pci_chipset; > u_int stick_get_timecount(struct timecounter *); > > struct timecounter stick_timecounter = { > - stick_get_timecount, NULL, ~0u, 0, "stick", 1000, NULL > + stick_get_timecount, NULL, ~0u, 0, "stick", 1000, NULL, 0 > }; > > /* > diff --git sys/arch/sparc64/sparc64/clock.c sys/arch/sparc64/sparc64/clock.c > index fd5e8a9c15b..5c2e47d386b 100644 > --- sys/arch/sparc64/sparc64/clock.c > +++ sys/arch/sparc64/sparc64/clock.c > @@ -109,13 +109,13 @@ struct cfdriver clock_cd = { > u_int tick_get_timecount(struct timecounter *); > > struct timecounter tick_timecounter = { > - tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL > + tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL, 0 > }; > > u_int sys_tick_get_timecount(struct timecounter *); > > struct timecounter sys_tick_timecounter = { > - sys_tick_get_timecount, NULL, ~0u, 0, "sys_tick", 1000, NULL > + sys_tick_get_timecount, NULL, ~0u, 0, "sys_tick", 1000, NULL, 0 > }; > > /* > diff --git sys/dev/acpi/acpihpet.c sys/dev/acpi/acpihpet.c > index d0ee72cec9b..13177a909da 100644 > --- sys/dev/acpi/acpihpet.c > +++ sys/dev/acpi/acpihpet.c > @@ -45,7 +45,9 @@ static struct timecounter hpet_timecounter = { > 0xffffffff, /* counter_mask (32 bits) */ > 0, /* frequency */ > 0, /* name */ > - 1000 /* quality */ > + 1000, /* quality */ > + NULL, /* private bits */ > + 0, /* expose to user */ > }; > > #define HPET_TIMERS 3 > diff --git sys/dev/acpi/acpitimer.c sys/dev/acpi/acpitimer.c > index cdc8c99a17a..89b5a397e47 100644 > --- sys/dev/acpi/acpitimer.c > +++ sys/dev/acpi/acpitimer.c > @@ -36,7 +36,9 @@ static struct timecounter acpi_timecounter = { > 0x00ffffff, /* counter_mask (24 bits) */ > ACPI_FREQUENCY, /* frequency */ > 0, /* name */ > - 1000 /* quality */ > + 1000, /* quality */ > + NULL, /* private bits */ > + 0, /* expose to user */ > }; > > struct acpitimer_softc { > diff --git sys/dev/pci/amdpm.c sys/dev/pci/amdpm.c > index 6df82858016..9610d5bc1f0 100644 > --- sys/dev/pci/amdpm.c > +++ sys/dev/pci/amdpm.c > @@ -82,7 +82,9 @@ static struct timecounter amdpm_timecounter = { > 0xffffff, /* counter_mask */ > AMDPM_FREQUENCY, /* frequency */ > "AMDPM", /* name */ > - 1000 /* quality */ > + 1000, /* quality */ > + NULL, /* private bits */ > + 0, /* expose to user */ > }; > > #define AMDPM_CONFREG 0x40 > diff --git sys/dev/pci/viapm.c sys/dev/pci/viapm.c > index db806eedf80..ce33cd175e6 100644 > --- sys/dev/pci/viapm.c > +++ sys/dev/pci/viapm.c > @@ -177,7 +177,9 @@ static struct timecounter viapm_timecounter = { > 0xffffff, /* counter_mask */ > VIAPM_FREQUENCY, /* frequency */ > "VIAPM", /* name */ > - 1000 /* quality */ > + 1000, /* quality */ > + NULL, /* private bits */ > + 0, /* expose to user */ > }; > > struct timeout viapm_timeout; > diff --git sys/dev/pv/hyperv.c sys/dev/pv/hyperv.c > index b32facdacb1..b9ee2feec4c 100644 > --- sys/dev/pv/hyperv.c > +++ sys/dev/pv/hyperv.c > @@ -141,7 +141,7 @@ struct { > }; > > struct timecounter hv_timecounter = { > - hv_gettime, 0, 0xffffffff, 10000000, "hyperv", 9001 > + hv_gettime, 0, 0xffffffff, 10000000, "hyperv", 9001, NULL, 0 > }; > > struct cfdriver hyperv_cd = { > diff --git sys/dev/pv/pvclock.c sys/dev/pv/pvclock.c > index 6b242f7448d..b80e4d2a484 100644 > --- sys/dev/pv/pvclock.c > +++ sys/dev/pv/pvclock.c > @@ -74,7 +74,7 @@ struct cfdriver pvclock_cd = { > }; > > struct timecounter pvclock_timecounter = { > - pvclock_get_timecount, NULL, ~0u, 0, NULL, -2000, NULL > + pvclock_get_timecount, NULL, ~0u, 0, NULL, -2000, NULL, 0 > }; > > int > diff --git sys/kern/exec_elf.c sys/kern/exec_elf.c > index 9b5b8eb3acf..59bc923a6fb 100644 > --- sys/kern/exec_elf.c > +++ sys/kern/exec_elf.c > @@ -124,7 +124,7 @@ extern char *syscallnames[]; > /* > * How many entries are in the AuxInfo array we pass to the process? > */ > -#define ELF_AUX_ENTRIES 8 > +#define ELF_AUX_ENTRIES 9 > > /* > * This is the OpenBSD ELF emul > @@ -860,6 +860,10 @@ exec_elf_fixup(struct proc *p, struct exec_package *epp) > a->au_v = ap->arg_entry; > a++; > > + a->au_id = AUX_openbsd_timekeep; > + a->au_v = p->p_p->ps_timekeep; > + a++; > + > a->au_id = AUX_null; > a->au_v = 0; > a++; > diff --git sys/kern/kern_exec.c sys/kern/kern_exec.c > index 20480c2fc28..8869f1fb89f 100644 > --- sys/kern/kern_exec.c > +++ sys/kern/kern_exec.c > @@ -64,6 +64,11 @@ > #include <uvm/uvm_extern.h> > #include <machine/tcb.h> > > +#include <sys/timetc.h> > + > +struct uvm_object *timekeep_object; > +struct timekeep* timekeep; > + > void unveil_destroy(struct process *ps); > > const struct kmem_va_mode kv_exec = { > @@ -76,6 +81,11 @@ const struct kmem_va_mode kv_exec = { > */ > int exec_sigcode_map(struct process *, struct emul *); > > +/* > + * Map the shared timekeep page. > + */ > +int exec_timekeep_map(struct process *); > + > /* > * If non-zero, stackgap_random specifies the upper limit of the random gap > size > * added to the fixed stack position. Must be n^2. > @@ -684,6 +694,9 @@ sys_execve(struct proc *p, void *v, register_t *retval) > /* map the process's signal trampoline code */ > if (exec_sigcode_map(pr, pack.ep_emul)) > goto free_pack_abort; > + /* map the process's timekeep page */ > + if (exec_timekeep_map(pr)) > + goto free_pack_abort; > > #ifdef __HAVE_EXEC_MD_MAP > /* perform md specific mappings that process might need */ > @@ -863,3 +876,41 @@ exec_sigcode_map(struct process *pr, struct emul *e) > > return (0); > } > + > +int > +exec_timekeep_map(struct process *pr) > +{ > + size_t timekeep_sz = sizeof(struct timekeep); > + > + /* > + * Similar to the sigcode object, except that there is a single timekeep > + * object, and not one per emulation. > + */ > + if (timekeep_object == NULL) { > + vaddr_t va; > + > + timekeep_object = uao_create(timekeep_sz, 0); > + uao_reference(timekeep_object); > + > + if (uvm_map(kernel_map, &va, round_page(timekeep_sz), > timekeep_object, > + 0, 0, UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | > PROT_WRITE, > + MAP_INHERIT_SHARE, MADV_RANDOM, 0))) { > + uao_detach(timekeep_object); > + return (ENOMEM); > + } > + > + timekeep = (struct timekeep *)va; > + timekeep->tk_major = 0; > + timekeep->tk_minor = 0; > + } > + > + uao_reference(timekeep_object); > + if (uvm_map(&pr->ps_vmspace->vm_map, &pr->ps_timekeep, > round_page(timekeep_sz), > + timekeep_object, 0, 0, UVM_MAPFLAG(PROT_READ, PROT_READ, > + MAP_INHERIT_COPY, MADV_RANDOM, 0))) { > + uao_detach(timekeep_object); > + return (ENOMEM); > + } > + > + return (0); > +} > diff --git sys/kern/kern_tc.c sys/kern/kern_tc.c > index 88d4a3379f9..47efbdd0b78 100644 > --- sys/kern/kern_tc.c > +++ sys/kern/kern_tc.c > @@ -63,7 +63,7 @@ dummy_get_timecount(struct timecounter *tc) > } > > static struct timecounter dummy_timecounter = { > - dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000 > + dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000, NULL, 0 > }; > > /* > @@ -479,6 +479,34 @@ tc_setclock(const struct timespec *ts) > #endif > } > > +void > +tc_update_timekeep(void) > +{ > + static struct timecounter *last_tc = NULL; > + struct timehands *th; > + > + if (timekeep == NULL) > + return; > + > + th = timehands; > + timekeep->tk_generation = 0; > + membar_producer(); > + timekeep->tk_scale = th->th_scale; > + timekeep->tk_offset_count = th->th_offset_count; > + timekeep->tk_offset = th->th_offset; > + timekeep->tk_naptime = th->th_naptime; > + timekeep->tk_boottime = th->th_boottime; > + if (last_tc != th->th_counter) { > + timekeep->tk_counter_mask = th->th_counter->tc_counter_mask; > + timekeep->tk_user = th->th_counter->tc_user; > + last_tc = th->th_counter; > + } > + membar_producer(); > + timekeep->tk_generation = th->th_generation; > + > + return; > +} > + > /* > * Initialize the next struct timehands in the ring and make > * it the active timehands. Along the way we might switch to a different > @@ -631,6 +659,8 @@ tc_windup(struct bintime *new_boottime, struct bintime > *new_offset, > time_uptime = th->th_offset.sec; > membar_producer(); > timehands = th; > + > + tc_update_timekeep(); > } > > /* Report or change the active timecounter hardware. */ > diff --git sys/sys/exec_elf.h sys/sys/exec_elf.h > index a40e0510273..3084ed595a6 100644 > --- sys/sys/exec_elf.h > +++ sys/sys/exec_elf.h > @@ -691,7 +691,8 @@ enum AuxID { > AUX_sun_uid = 2000, /* euid */ > AUX_sun_ruid = 2001, /* ruid */ > AUX_sun_gid = 2002, /* egid */ > - AUX_sun_rgid = 2003 /* rgid */ > + AUX_sun_rgid = 2003, /* rgid */ > + AUX_openbsd_timekeep = 4000, /* userland clock_gettime */ > }; > > struct elf_args { > diff --git sys/sys/proc.h sys/sys/proc.h > index 357c0c0d52c..c6d54572bdd 100644 > --- sys/sys/proc.h > +++ sys/sys/proc.h > @@ -242,6 +242,7 @@ struct process { > char ps_comm[MAXCOMLEN+1]; > > vaddr_t ps_strings; /* User pointers to argv/env */ > + vaddr_t ps_timekeep; /* User pointer to timekeep */ > vaddr_t ps_sigcode; /* User pointer to the signal code */ > vaddr_t ps_sigcoderet; /* User pointer to sigreturn retPC */ > u_long ps_sigcookie; > diff --git sys/sys/time.h sys/sys/time.h > index e758a64ce07..bcd3acd034d 100644 > --- sys/sys/time.h > +++ sys/sys/time.h > @@ -163,7 +163,7 @@ struct clockinfo { > }; > #endif /* __BSD_VISIBLE */ > > -#if defined(_KERNEL) || defined(_STANDALONE) > +#if defined(_KERNEL) || defined(_STANDALONE) || defined (_LIBC) > #include <sys/_time.h> > > /* Time expressed as seconds and fractions of a second + operations on it. */ > @@ -171,6 +171,9 @@ struct bintime { > time_t sec; > uint64_t frac; > }; > +#endif > + > +#if defined(_KERNEL) || defined(_STANDALONE) > > #define bintimecmp(btp, ctp, cmp) \ > ((btp)->sec == (ctp)->sec ? \ > diff --git sys/sys/timetc.h sys/sys/timetc.h > index ce81c3475a0..22658b00da2 100644 > --- sys/sys/timetc.h > +++ sys/sys/timetc.h > @@ -24,7 +24,7 @@ > #ifndef _SYS_TIMETC_H_ > #define _SYS_TIMETC_H_ > > -#ifndef _KERNEL > +#if !defined(_KERNEL) && !defined(_LIBC) > #error "no user-serviceable parts inside" > #endif > > @@ -80,6 +80,8 @@ struct timecounter { > */ > void *tc_priv; /* [I] */ > /* Pointer to the timecounter's private parts. */ > + int tc_user; /* [I] */ > + /* Expose this timecounter to userland. */ > SLIST_ENTRY(timecounter) tc_next; /* [I] */ > /* Pointer to the next timecounter. */ > int64_t tc_freq_adj; /* [tw] */ > @@ -88,11 +90,31 @@ struct timecounter { > /* Precision of the counter. Computed in tc_init(). */ > }; > > +struct timekeep { > + uint32_t tk_major; /* version major number */ > + uint32_t tk_minor; /* version minor number */ > + > + /* timehands members */ > + uint64_t tk_scale; > + u_int tk_offset_count; > + struct bintime tk_offset; > + struct bintime tk_naptime; > + struct bintime tk_boottime; > + volatile u_int tk_generation; > + > + /* timecounter members */ > + int tk_user; > + u_int tk_counter_mask; > +}; > + > struct rwlock; > extern struct rwlock tc_lock; > > extern struct timecounter *timecounter; > > +extern struct uvm_object *timekeep_object; > +extern struct timekeep *timekeep; > + > u_int64_t tc_getfrequency(void); > u_int64_t tc_getprecision(void); > void tc_init(struct timecounter *tc); >