diff options
author | 2020-07-06 13:33:05 +0000 | |
---|---|---|
committer | 2020-07-06 13:33:05 +0000 | |
commit | d82e6535c6efd8305182f77041b2246ccfae1196 (patch) | |
tree | d28dc130334c17949d90330ecbb2121294b899ff /lib/libc/sys/microtime.c | |
parent | sync (diff) | |
download | wireguard-openbsd-d82e6535c6efd8305182f77041b2246ccfae1196.tar.xz wireguard-openbsd-d82e6535c6efd8305182f77041b2246ccfae1196.zip |
Add support for timeconting in userland.
This diff exposes parts of clock_gettime(2) and gettimeofday(2) to
userland via libc eliberating processes from the need for a context
switch everytime they want to count the passage of time.
If a timecounter clock can be exposed to userland than it needs to set
its tc_user member to a non-zero value. Tested with one or multiple
counters per architecture.
The timing data is shared through a pointer found in the new ELF
auxiliary vector AUX_openbsd_timekeep containing timehands information
that is frequently updated by the kernel.
Timing differences between the last kernel update and the current time
are adjusted in userland by the tc_get_timecount() function inside the
MD usertc.c file.
This permits a much more responsive environment, quite visible in
browsers, office programs and gaming (apparently one is are able to fly
in Minecraft now).
Tested by robert@, sthen@, naddy@, kmos@, phessler@, and many others!
OK from at least kettenis@, cheloha@, naddy@, sthen@
Diffstat (limited to 'lib/libc/sys/microtime.c')
-rw-r--r-- | lib/libc/sys/microtime.c | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/lib/libc/sys/microtime.c b/lib/libc/sys/microtime.c new file mode 100644 index 00000000000..e85a86a78de --- /dev/null +++ b/lib/libc/sys/microtime.c @@ -0,0 +1,138 @@ +/* $OpenBSD: microtime.c,v 1.1 2020/07/06 13:33:06 pirofti Exp $ */ +/* + * Copyright (c) 2000 Poul-Henning Kamp <phk@FreeBSD.org> + * Copyright (c) 2020 Paul Irofti <paul@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 int +tc_delta(struct timekeep *tk, u_int *delta) +{ + u_int tc; + + if (_tc_get_timecount(tk, &tc)) + return -1; + *delta = (tc - tk->tk_offset_count) & tk->tk_counter_mask; + return 0; +} + +static int +binuptime(struct bintime *bt, struct timekeep *tk) +{ + u_int gen, delta; + + do { + gen = tk->tk_generation; + membar_consumer(); + *bt = tk->tk_offset; + if (tc_delta(tk, &delta)) + return -1; + bintimeaddfrac(bt, tk->tk_scale * delta, bt); + membar_consumer(); + } while (gen == 0 || gen != tk->tk_generation); + + return 0; +} + +static int +binruntime(struct bintime *bt, struct timekeep *tk) +{ + u_int gen, delta; + + do { + gen = tk->tk_generation; + membar_consumer(); + if (tc_delta(tk, &delta)) + return -1; + bintimeaddfrac(&tk->tk_offset, tk->tk_scale * delta, bt); + bintimesub(bt, &tk->tk_naptime, bt); + membar_consumer(); + } while (gen == 0 || gen != tk->tk_generation); + + return 0; +} + +static int +bintime(struct bintime *bt, struct timekeep *tk) +{ + u_int gen, delta; + + do { + gen = tk->tk_generation; + membar_consumer(); + *bt = tk->tk_offset; + if (tc_delta(tk, &delta)) + return -1; + bintimeaddfrac(bt, tk->tk_scale * delta, bt); + bintimeadd(bt, &tk->tk_boottime, bt); + membar_consumer(); + } while (gen == 0 || gen != tk->tk_generation); + + return 0; +} + +int +_microtime(struct timeval *tvp, struct timekeep *tk) +{ + struct bintime bt; + + if (bintime(&bt, tk)) + return -1; + BINTIME_TO_TIMEVAL(&bt, tvp); + return 0; +} + +int +_nanotime(struct timespec *tsp, struct timekeep *tk) +{ + struct bintime bt; + + if (bintime(&bt, tk)) + return -1; + BINTIME_TO_TIMESPEC(&bt, tsp); + return 0; +} + +int +_nanoruntime(struct timespec *ts, struct timekeep *tk) +{ + struct bintime bt; + + if (binruntime(&bt, tk)) + return -1; + BINTIME_TO_TIMESPEC(&bt, ts); + return 0; +} + + +int +_nanouptime(struct timespec *tsp, struct timekeep *tk) +{ + struct bintime bt; + + if (binuptime(&bt, tk)) + return -1; + BINTIME_TO_TIMESPEC(&bt, tsp); + return 0; +} |