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  //go: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 nanotime1() 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