...

Source file src/runtime/vdso_freebsd.go

     1	// Copyright 2018 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	// +build freebsd
     6	
     7	package runtime
     8	
     9	import (
    10		"runtime/internal/atomic"
    11		"unsafe"
    12	)
    13	
    14	const _VDSO_TH_NUM = 4 // defined in <sys/vdso.h> #ifdef _KERNEL
    15	
    16	var timekeepSharedPage *vdsoTimekeep
    17	
    18	//go:nosplit
    19	func (bt *bintime) Add(bt2 *bintime) {
    20		u := bt.frac
    21		bt.frac += bt2.frac
    22		if u > bt.frac {
    23			bt.sec++
    24		}
    25		bt.sec += bt2.sec
    26	}
    27	
    28	//go:nosplit
    29	func (bt *bintime) AddX(x uint64) {
    30		u := bt.frac
    31		bt.frac += x
    32		if u > bt.frac {
    33			bt.sec++
    34		}
    35	}
    36	
    37	var (
    38		// binuptimeDummy is used in binuptime as the address of an atomic.Load, to simulate
    39		// an atomic_thread_fence_acq() call which behaves as an instruction reordering and
    40		// memory barrier.
    41		binuptimeDummy uint32
    42	
    43		zeroBintime bintime
    44	)
    45	
    46	// based on /usr/src/lib/libc/sys/__vdso_gettimeofday.c
    47	//
    48	//go:nosplit
    49	func binuptime(abs bool) (bt bintime) {
    50		timehands := (*[_VDSO_TH_NUM]vdsoTimehands)(add(unsafe.Pointer(timekeepSharedPage), vdsoTimekeepSize))
    51		for {
    52			if timekeepSharedPage.enabled == 0 {
    53				return zeroBintime
    54			}
    55	
    56			curr := atomic.Load(&timekeepSharedPage.current) // atomic_load_acq_32
    57			th := &timehands[curr]
    58			gen := atomic.Load(&th.gen) // atomic_load_acq_32
    59			bt = th.offset
    60	
    61			if tc, ok := th.getTimecounter(); !ok {
    62				return zeroBintime
    63			} else {
    64				delta := (tc - th.offset_count) & th.counter_mask
    65				bt.AddX(th.scale * uint64(delta))
    66			}
    67			if abs {
    68				bt.Add(&th.boottime)
    69			}
    70	
    71			atomic.Load(&binuptimeDummy) // atomic_thread_fence_acq()
    72			if curr == timekeepSharedPage.current && gen != 0 && gen == th.gen {
    73				break
    74			}
    75		}
    76		return bt
    77	}
    78	
    79	//go:nosplit
    80	func vdsoClockGettime(clockID int32) bintime {
    81		if timekeepSharedPage == nil || timekeepSharedPage.ver != _VDSO_TK_VER_CURR {
    82			return zeroBintime
    83		}
    84		abs := false
    85		switch clockID {
    86		case _CLOCK_MONOTONIC:
    87			/* ok */
    88		case _CLOCK_REALTIME:
    89			abs = true
    90		default:
    91			return zeroBintime
    92		}
    93		return binuptime(abs)
    94	}
    95	
    96	func fallback_nanotime() int64
    97	func fallback_walltime() (sec int64, nsec int32)
    98	
    99	//go:nosplit
   100	func nanotime() int64 {
   101		bt := vdsoClockGettime(_CLOCK_MONOTONIC)
   102		if bt == zeroBintime {
   103			return fallback_nanotime()
   104		}
   105		return int64((1e9 * uint64(bt.sec)) + ((1e9 * uint64(bt.frac>>32)) >> 32))
   106	}
   107	
   108	func walltime() (sec int64, nsec int32) {
   109		bt := vdsoClockGettime(_CLOCK_REALTIME)
   110		if bt == zeroBintime {
   111			return fallback_walltime()
   112		}
   113		return int64(bt.sec), int32((1e9 * uint64(bt.frac>>32)) >> 32)
   114	}
   115	

View as plain text