aboutsummaryrefslogtreecommitdiff
path: root/lib/libc/sys/__vdso_gettimeofday.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/sys/__vdso_gettimeofday.c')
-rw-r--r--lib/libc/sys/__vdso_gettimeofday.c25
1 files changed, 14 insertions, 11 deletions
diff --git a/lib/libc/sys/__vdso_gettimeofday.c b/lib/libc/sys/__vdso_gettimeofday.c
index a305173b3ed8c..b3527fa4de533 100644
--- a/lib/libc/sys/__vdso_gettimeofday.c
+++ b/lib/libc/sys/__vdso_gettimeofday.c
@@ -42,6 +42,15 @@ tc_delta(const struct vdso_timehands *th)
th->th_counter_mask);
}
+/*
+ * Calculate the absolute or boot-relative time from the
+ * machine-specific fast timecounter and the published timehands
+ * structure read from the shared page.
+ *
+ * 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
+ * is based on the kernel implementation.
+ */
static int
binuptime(struct bintime *bt, struct vdso_timekeep *tk, int abs)
{
@@ -52,27 +61,21 @@ binuptime(struct bintime *bt, struct vdso_timekeep *tk, int abs)
if (!tk->tk_enabled)
return (ENOSYS);
- /*
- * XXXKIB. The load of tk->tk_current should use
- * atomic_load_acq_32 to provide load barrier. But
- * since tk points to r/o mapped page, x86
- * implementation of atomic_load_acq faults.
- */
- curr = tk->tk_current;
- rmb();
+ curr = atomic_load_acq_32(&tk->tk_current);
th = &tk->tk_th[curr];
if (th->th_algo != VDSO_TH_ALGO_1)
return (ENOSYS);
- gen = th->th_gen;
+ gen = atomic_load_acq_32(&th->th_gen);
*bt = th->th_offset;
bintime_addx(bt, th->th_scale * tc_delta(th));
if (abs)
bintime_add(bt, &th->th_boottime);
/*
- * Barrier for load of both tk->tk_current and th->th_gen.
+ * Ensure that the load of th_offset is completed
+ * before the load of th_gen.
*/
- rmb();
+ atomic_thread_fence_acq();
} while (curr != tk->tk_current || gen == 0 || gen != th->th_gen);
return (0);
}