// Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build freebsd package runtime import ( "runtime/internal/atomic" "unsafe" ) const _VDSO_TH_NUM = 4 // defined in <sys/vdso.h> #ifdef _KERNEL var timekeepSharedPage *vdsoTimekeep //go:nosplit func (bt *bintime) Add(bt2 *bintime) { u := bt.frac bt.frac += bt2.frac if u > bt.frac { bt.sec++ } bt.sec += bt2.sec } //go:nosplit func (bt *bintime) AddX(x uint64) { u := bt.frac bt.frac += x if u > bt.frac { bt.sec++ } } var ( // binuptimeDummy is used in binuptime as the address of an atomic.Load, to simulate // an atomic_thread_fence_acq() call which behaves as an instruction reordering and // memory barrier. binuptimeDummy uint32 zeroBintime bintime ) // based on /usr/src/lib/libc/sys/__vdso_gettimeofday.c // //go:nosplit func binuptime(abs bool) (bt bintime) { timehands := (*[_VDSO_TH_NUM]vdsoTimehands)(add(unsafe.Pointer(timekeepSharedPage), vdsoTimekeepSize)) for { if timekeepSharedPage.enabled == 0 { return zeroBintime } curr := atomic.Load(&timekeepSharedPage.current) // atomic_load_acq_32 th := &timehands[curr] gen := atomic.Load(&th.gen) // atomic_load_acq_32 bt = th.offset if tc, ok := th.getTimecounter(); !ok { return zeroBintime } else { delta := (tc - th.offset_count) & th.counter_mask bt.AddX(th.scale * uint64(delta)) } if abs { bt.Add(&th.boottime) } atomic.Load(&binuptimeDummy) // atomic_thread_fence_acq() if curr == timekeepSharedPage.current && gen != 0 && gen == th.gen { break } } return bt } //go:nosplit func vdsoClockGettime(clockID int32) bintime { if timekeepSharedPage == nil || timekeepSharedPage.ver != _VDSO_TK_VER_CURR { return zeroBintime } abs := false switch clockID { case _CLOCK_MONOTONIC: /* ok */ case _CLOCK_REALTIME: abs = true default: return zeroBintime } return binuptime(abs) } func fallback_nanotime() int64 func fallback_walltime() (sec int64, nsec int32) //go:nosplit func nanotime() int64 { bt := vdsoClockGettime(_CLOCK_MONOTONIC) if bt == zeroBintime { return fallback_nanotime() } return int64((1e9 * uint64(bt.sec)) + ((1e9 * uint64(bt.frac>>32)) >> 32)) } func walltime() (sec int64, nsec int32) { bt := vdsoClockGettime(_CLOCK_REALTIME) if bt == zeroBintime { return fallback_walltime() } return int64(bt.sec), int32((1e9 * uint64(bt.frac>>32)) >> 32) }