github.com/fjballest/golang@v0.0.0-20151209143359-e4c5fe594ca8/src/runtime/os1_freebsd.go (about)

     1  // Copyright 2011 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  package runtime
     6  
     7  import (
     8  	"runtime/internal/sys"
     9  	"unsafe"
    10  )
    11  
    12  // From FreeBSD's <sys/sysctl.h>
    13  const (
    14  	_CTL_HW  = 6
    15  	_HW_NCPU = 3
    16  )
    17  
    18  var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
    19  
    20  func getncpu() int32 {
    21  	mib := [2]uint32{_CTL_HW, _HW_NCPU}
    22  	out := uint32(0)
    23  	nout := unsafe.Sizeof(out)
    24  	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
    25  	if ret >= 0 {
    26  		return int32(out)
    27  	}
    28  	return 1
    29  }
    30  
    31  // FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
    32  // thus the code is largely similar. See Linux implementation
    33  // and lock_futex.go for comments.
    34  
    35  //go:nosplit
    36  func futexsleep(addr *uint32, val uint32, ns int64) {
    37  	systemstack(func() {
    38  		futexsleep1(addr, val, ns)
    39  	})
    40  }
    41  
    42  func futexsleep1(addr *uint32, val uint32, ns int64) {
    43  	var tsp *timespec
    44  	if ns >= 0 {
    45  		var ts timespec
    46  		ts.tv_nsec = 0
    47  		ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
    48  		tsp = &ts
    49  	}
    50  	ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, nil, tsp)
    51  	if ret >= 0 || ret == -_EINTR {
    52  		return
    53  	}
    54  	print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n")
    55  	*(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
    56  }
    57  
    58  //go:nosplit
    59  func futexwakeup(addr *uint32, cnt uint32) {
    60  	ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, nil, nil)
    61  	if ret >= 0 {
    62  		return
    63  	}
    64  
    65  	systemstack(func() {
    66  		print("umtx_wake_addr=", addr, " ret=", ret, "\n")
    67  	})
    68  }
    69  
    70  func thr_start()
    71  
    72  // May run with m.p==nil, so write barriers are not allowed.
    73  //go:nowritebarrier
    74  func newosproc(mp *m, stk unsafe.Pointer) {
    75  	if false {
    76  		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " thr_start=", funcPC(thr_start), " id=", mp.id, " ostk=", &mp, "\n")
    77  	}
    78  
    79  	// NOTE(rsc): This code is confused. stackbase is the top of the stack
    80  	// and is equal to stk. However, it's working, so I'm not changing it.
    81  	param := thrparam{
    82  		start_func: funcPC(thr_start),
    83  		arg:        unsafe.Pointer(mp),
    84  		stack_base: mp.g0.stack.hi,
    85  		stack_size: uintptr(stk) - mp.g0.stack.hi,
    86  		child_tid:  unsafe.Pointer(&mp.procid),
    87  		parent_tid: nil,
    88  		tls_base:   unsafe.Pointer(&mp.tls[0]),
    89  		tls_size:   unsafe.Sizeof(mp.tls),
    90  	}
    91  
    92  	var oset sigset
    93  	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
    94  	thr_new(&param, int32(unsafe.Sizeof(param)))
    95  	sigprocmask(_SIG_SETMASK, &oset, nil)
    96  }
    97  
    98  func osinit() {
    99  	ncpu = getncpu()
   100  }
   101  
   102  var urandom_dev = []byte("/dev/urandom\x00")
   103  
   104  //go:nosplit
   105  func getRandomData(r []byte) {
   106  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   107  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   108  	closefd(fd)
   109  	extendRandom(r, int(n))
   110  }
   111  
   112  func goenvs() {
   113  	goenvs_unix()
   114  }
   115  
   116  // Called to initialize a new m (including the bootstrap m).
   117  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   118  func mpreinit(mp *m) {
   119  	mp.gsignal = malg(32 * 1024)
   120  	mp.gsignal.m = mp
   121  }
   122  
   123  //go:nosplit
   124  func msigsave(mp *m) {
   125  	sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
   126  }
   127  
   128  //go:nosplit
   129  func msigrestore(mp *m) {
   130  	sigprocmask(_SIG_SETMASK, &mp.sigmask, nil)
   131  }
   132  
   133  //go:nosplit
   134  func sigblock() {
   135  	sigprocmask(_SIG_SETMASK, &sigset_all, nil)
   136  }
   137  
   138  // Called to initialize a new m (including the bootstrap m).
   139  // Called on the new thread, can not allocate memory.
   140  func minit() {
   141  	_g_ := getg()
   142  
   143  	// m.procid is a uint64, but thr_new writes a uint32 on 32-bit systems.
   144  	// Fix it up. (Only matters on big-endian, but be clean anyway.)
   145  	if sys.PtrSize == 4 {
   146  		_g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid)))
   147  	}
   148  
   149  	// Initialize signal handling.
   150  	signalstack(&_g_.m.gsignal.stack)
   151  
   152  	// restore signal mask from m.sigmask and unblock essential signals
   153  	nmask := _g_.m.sigmask
   154  	for i := range sigtable {
   155  		if sigtable[i].flags&_SigUnblock != 0 {
   156  			nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
   157  		}
   158  	}
   159  	sigprocmask(_SIG_SETMASK, &nmask, nil)
   160  }
   161  
   162  // Called from dropm to undo the effect of an minit.
   163  //go:nosplit
   164  func unminit() {
   165  	signalstack(nil)
   166  }
   167  
   168  func memlimit() uintptr {
   169  	/*
   170  		TODO: Convert to Go when something actually uses the result.
   171  		Rlimit rl;
   172  		extern byte runtime·text[], runtime·end[];
   173  		uintptr used;
   174  
   175  		if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
   176  			return 0;
   177  		if(rl.rlim_cur >= 0x7fffffff)
   178  			return 0;
   179  
   180  		// Estimate our VM footprint excluding the heap.
   181  		// Not an exact science: use size of binary plus
   182  		// some room for thread stacks.
   183  		used = runtime·end - runtime·text + (64<<20);
   184  		if(used >= rl.rlim_cur)
   185  			return 0;
   186  
   187  		// If there's not at least 16 MB left, we're probably
   188  		// not going to be able to do much.  Treat as no limit.
   189  		rl.rlim_cur -= used;
   190  		if(rl.rlim_cur < (16<<20))
   191  			return 0;
   192  
   193  		return rl.rlim_cur - used;
   194  	*/
   195  
   196  	return 0
   197  }
   198  
   199  func sigtramp()
   200  
   201  type sigactiont struct {
   202  	sa_handler uintptr
   203  	sa_flags   int32
   204  	sa_mask    sigset
   205  }
   206  
   207  func setsig(i int32, fn uintptr, restart bool) {
   208  	var sa sigactiont
   209  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
   210  	if restart {
   211  		sa.sa_flags |= _SA_RESTART
   212  	}
   213  	sa.sa_mask = sigset_all
   214  	if fn == funcPC(sighandler) {
   215  		fn = funcPC(sigtramp)
   216  	}
   217  	sa.sa_handler = fn
   218  	sigaction(i, &sa, nil)
   219  }
   220  
   221  func setsigstack(i int32) {
   222  	throw("setsigstack")
   223  }
   224  
   225  func getsig(i int32) uintptr {
   226  	var sa sigactiont
   227  	sigaction(i, nil, &sa)
   228  	if sa.sa_handler == funcPC(sigtramp) {
   229  		return funcPC(sighandler)
   230  	}
   231  	return sa.sa_handler
   232  }
   233  
   234  //go:nosplit
   235  func signalstack(s *stack) {
   236  	var st stackt
   237  	if s == nil {
   238  		st.ss_flags = _SS_DISABLE
   239  	} else {
   240  		st.ss_sp = s.lo
   241  		st.ss_size = s.hi - s.lo
   242  		st.ss_flags = 0
   243  	}
   244  	sigaltstack(&st, nil)
   245  }
   246  
   247  func updatesigmask(m [(_NSIG + 31) / 32]uint32) {
   248  	var mask sigset
   249  	copy(mask.__bits[:], m[:])
   250  	sigprocmask(_SIG_SETMASK, &mask, nil)
   251  }
   252  
   253  func unblocksig(sig int32) {
   254  	var mask sigset
   255  	mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
   256  	sigprocmask(_SIG_UNBLOCK, &mask, nil)
   257  }