Changeset View
Changeset View
Standalone View
Standalone View
lib/libc/sys/__vdso_gettimeofday.c
Show All 26 Lines | |||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/elf.h> | #include <sys/elf.h> | ||||
#include <sys/time.h> | #include <sys/time.h> | ||||
#include <sys/vdso.h> | #include <sys/vdso.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <stdbool.h> | |||||
#include <strings.h> | #include <strings.h> | ||||
#include <time.h> | #include <time.h> | ||||
#include <machine/atomic.h> | #include <machine/atomic.h> | ||||
#include "libc_private.h" | #include "libc_private.h" | ||||
static int | static int | ||||
tc_delta(const struct vdso_timehands *th, u_int *delta) | tc_delta(const struct vdso_timehands *th, u_int *delta) | ||||
{ | { | ||||
Show All 11 Lines | |||||
* machine-specific fast timecounter and the published timehands | * machine-specific fast timecounter and the published timehands | ||||
* structure read from the shared page. | * structure read from the shared page. | ||||
* | * | ||||
* The lockless reading scheme is similar to the one used to read the | * The lockless reading scheme is similar to the one used to read the | ||||
* in-kernel timehands, see sys/kern/kern_tc.c:binuptime(). This code | * in-kernel timehands, see sys/kern/kern_tc.c:binuptime(). This code | ||||
* is based on the kernel implementation. | * is based on the kernel implementation. | ||||
*/ | */ | ||||
static int | static int | ||||
binuptime(struct bintime *bt, struct vdso_timekeep *tk, int abs) | binuptime(struct bintime *bt, struct vdso_timekeep *tk, bool abs) | ||||
{ | { | ||||
struct vdso_timehands *th; | struct vdso_timehands *th; | ||||
uint32_t curr, gen; | uint32_t curr, gen; | ||||
uint64_t scale, x; | uint64_t scale, x; | ||||
u_int delta, scale_bits; | u_int delta, scale_bits; | ||||
int error; | int error; | ||||
do { | do { | ||||
Show All 29 Lines | #endif | ||||
* Ensure that the load of th_offset is completed | * Ensure that the load of th_offset is completed | ||||
* before the load of th_gen. | * before the load of th_gen. | ||||
*/ | */ | ||||
atomic_thread_fence_acq(); | atomic_thread_fence_acq(); | ||||
} while (curr != tk->tk_current || gen == 0 || gen != th->th_gen); | } while (curr != tk->tk_current || gen == 0 || gen != th->th_gen); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | |||||
getnanouptime(struct bintime *bt, struct vdso_timekeep *tk) | |||||
{ | |||||
struct vdso_timehands *th; | |||||
uint32_t curr, gen; | |||||
do { | |||||
if (!tk->tk_enabled) | |||||
return (ENOSYS); | |||||
curr = atomic_load_acq_32(&tk->tk_current); | |||||
th = &tk->tk_th[curr]; | |||||
gen = atomic_load_acq_32(&th->th_gen); | |||||
*bt = th->th_offset; | |||||
/* | |||||
* Ensure that the load of th_offset is completed | |||||
* before the load of th_gen. | |||||
*/ | |||||
atomic_thread_fence_acq(); | |||||
} while (curr != tk->tk_current || gen == 0 || gen != th->th_gen); | |||||
return (0); | |||||
} | |||||
static struct vdso_timekeep *tk; | static struct vdso_timekeep *tk; | ||||
#pragma weak __vdso_gettimeofday | #pragma weak __vdso_gettimeofday | ||||
int | int | ||||
__vdso_gettimeofday(struct timeval *tv, struct timezone *tz) | __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) | ||||
{ | { | ||||
struct bintime bt; | struct bintime bt; | ||||
int error; | int error; | ||||
Show All 14 Lines | __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) | ||||
return (0); | return (0); | ||||
} | } | ||||
#pragma weak __vdso_clock_gettime | #pragma weak __vdso_clock_gettime | ||||
int | int | ||||
__vdso_clock_gettime(clockid_t clock_id, struct timespec *ts) | __vdso_clock_gettime(clockid_t clock_id, struct timespec *ts) | ||||
{ | { | ||||
struct bintime bt; | struct bintime bt; | ||||
int abs, error; | int error; | ||||
if (tk == NULL) { | if (tk == NULL) { | ||||
error = _elf_aux_info(AT_TIMEKEEP, &tk, sizeof(tk)); | error = _elf_aux_info(AT_TIMEKEEP, &tk, sizeof(tk)); | ||||
if (error != 0 || tk == NULL) | if (error != 0 || tk == NULL) | ||||
return (ENOSYS); | return (ENOSYS); | ||||
} | } | ||||
if (tk->tk_ver != VDSO_TK_VER_CURR) | if (tk->tk_ver != VDSO_TK_VER_CURR) | ||||
return (ENOSYS); | return (ENOSYS); | ||||
switch (clock_id) { | switch (clock_id) { | ||||
case CLOCK_REALTIME: | case CLOCK_REALTIME: | ||||
case CLOCK_REALTIME_PRECISE: | case CLOCK_REALTIME_PRECISE: | ||||
case CLOCK_REALTIME_FAST: | case CLOCK_REALTIME_FAST: | ||||
case CLOCK_SECOND: | case CLOCK_SECOND: | ||||
abs = 1; | error = binuptime(&bt, tk, true); | ||||
break; | break; | ||||
case CLOCK_MONOTONIC: | case CLOCK_MONOTONIC: | ||||
case CLOCK_MONOTONIC_PRECISE: | case CLOCK_MONOTONIC_PRECISE: | ||||
case CLOCK_MONOTONIC_FAST: | |||||
case CLOCK_UPTIME: | case CLOCK_UPTIME: | ||||
case CLOCK_UPTIME_PRECISE: | case CLOCK_UPTIME_PRECISE: | ||||
error = binuptime(&bt, tk, false); | |||||
break; | |||||
case CLOCK_MONOTONIC_FAST: | |||||
case CLOCK_UPTIME_FAST: | case CLOCK_UPTIME_FAST: | ||||
abs = 0; | error = getnanouptime(&bt, tk); | ||||
break; | break; | ||||
default: | default: | ||||
return (ENOSYS); | error = ENOSYS; | ||||
break; | |||||
} | } | ||||
error = binuptime(&bt, tk, abs); | |||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
bintime2timespec(&bt, ts); | bintime2timespec(&bt, ts); | ||||
if (clock_id == CLOCK_SECOND) | if (clock_id == CLOCK_SECOND) | ||||
ts->tv_nsec = 0; | ts->tv_nsec = 0; | ||||
return (0); | return (0); | ||||
} | } |