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  	"internal/runtime/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  		if curr >= uint32(len(timehands)) {
    58  			return zeroBintime
    59  		}
    60  		th := &timehands[curr]
    61  		gen := atomic.Load(&th.gen) // atomic_load_acq_32
    62  		bt = th.offset
    63  
    64  		if tc, ok := th.getTimecounter(); !ok {
    65  			return zeroBintime
    66  		} else {
    67  			delta := (tc - th.offset_count) & th.counter_mask
    68  			bt.AddX(th.scale * uint64(delta))
    69  		}
    70  		if abs {
    71  			bt.Add(&th.boottime)
    72  		}
    73  
    74  		atomic.Load(&binuptimeDummy) // atomic_thread_fence_acq()
    75  		if curr == timekeepSharedPage.current && gen != 0 && gen == th.gen {
    76  			break
    77  		}
    78  	}
    79  	return bt
    80  }
    81  
    82  //go:nosplit
    83  func vdsoClockGettime(clockID int32) bintime {
    84  	if timekeepSharedPage == nil || timekeepSharedPage.ver != _VDSO_TK_VER_CURR {
    85  		return zeroBintime
    86  	}
    87  	abs := false
    88  	switch clockID {
    89  	case _CLOCK_MONOTONIC:
    90  		/* ok */
    91  	case _CLOCK_REALTIME:
    92  		abs = true
    93  	default:
    94  		return zeroBintime
    95  	}
    96  	return binuptime(abs)
    97  }
    98  
    99  func fallback_nanotime() int64
   100  func fallback_walltime() (sec int64, nsec int32)
   101  
   102  //go:nosplit
   103  func nanotime1() int64 {
   104  	bt := vdsoClockGettime(_CLOCK_MONOTONIC)
   105  	if bt == zeroBintime {
   106  		return fallback_nanotime()
   107  	}
   108  	return int64((1e9 * uint64(bt.sec)) + ((1e9 * uint64(bt.frac>>32)) >> 32))
   109  }
   110  
   111  func walltime() (sec int64, nsec int32) {
   112  	bt := vdsoClockGettime(_CLOCK_REALTIME)
   113  	if bt == zeroBintime {
   114  		return fallback_walltime()
   115  	}
   116  	return int64(bt.sec), int32((1e9 * uint64(bt.frac>>32)) >> 32)
   117  }
   118  

View as plain text