...

Source file src/runtime/os_dragonfly.go

Documentation: runtime

     1  // Copyright 2014 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  	"internal/abi"
     9  	"internal/goarch"
    10  	"unsafe"
    11  )
    12  
    13  const (
    14  	_NSIG        = 33
    15  	_SI_USER     = 0
    16  	_SS_DISABLE  = 4
    17  	_SIG_BLOCK   = 1
    18  	_SIG_UNBLOCK = 2
    19  	_SIG_SETMASK = 3
    20  )
    21  
    22  type mOS struct{}
    23  
    24  //go:noescape
    25  func lwp_create(param *lwpparams) int32
    26  
    27  //go:noescape
    28  func sigaltstack(new, old *stackt)
    29  
    30  //go:noescape
    31  func sigaction(sig uint32, new, old *sigactiont)
    32  
    33  //go:noescape
    34  func sigprocmask(how int32, new, old *sigset)
    35  
    36  //go:noescape
    37  func setitimer(mode int32, new, old *itimerval)
    38  
    39  //go:noescape
    40  func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
    41  
    42  func raiseproc(sig uint32)
    43  
    44  func lwp_gettid() int32
    45  func lwp_kill(pid, tid int32, sig int)
    46  
    47  //go:noescape
    48  func sys_umtx_sleep(addr *uint32, val, timeout int32) int32
    49  
    50  //go:noescape
    51  func sys_umtx_wakeup(addr *uint32, val int32) int32
    52  
    53  func osyield()
    54  
    55  //go:nosplit
    56  func osyield_no_g() {
    57  	osyield()
    58  }
    59  
    60  func kqueue() int32
    61  
    62  //go:noescape
    63  func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
    64  
    65  func pipe2(flags int32) (r, w int32, errno int32)
    66  func fcntl(fd, cmd, arg int32) (ret int32, errno int32)
    67  
    68  func issetugid() int32
    69  
    70  // From DragonFly's <sys/sysctl.h>
    71  const (
    72  	_CTL_HW      = 6
    73  	_HW_NCPU     = 3
    74  	_HW_PAGESIZE = 7
    75  )
    76  
    77  var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
    78  
    79  func getncpu() int32 {
    80  	mib := [2]uint32{_CTL_HW, _HW_NCPU}
    81  	out := uint32(0)
    82  	nout := unsafe.Sizeof(out)
    83  	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
    84  	if ret >= 0 {
    85  		return int32(out)
    86  	}
    87  	return 1
    88  }
    89  
    90  func getPageSize() uintptr {
    91  	mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
    92  	out := uint32(0)
    93  	nout := unsafe.Sizeof(out)
    94  	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
    95  	if ret >= 0 {
    96  		return uintptr(out)
    97  	}
    98  	return 0
    99  }
   100  
   101  //go:nosplit
   102  func futexsleep(addr *uint32, val uint32, ns int64) {
   103  	systemstack(func() {
   104  		futexsleep1(addr, val, ns)
   105  	})
   106  }
   107  
   108  func futexsleep1(addr *uint32, val uint32, ns int64) {
   109  	var timeout int32
   110  	if ns >= 0 {
   111  		// The timeout is specified in microseconds - ensure that we
   112  		// do not end up dividing to zero, which would put us to sleep
   113  		// indefinitely...
   114  		timeout = timediv(ns, 1000, nil)
   115  		if timeout == 0 {
   116  			timeout = 1
   117  		}
   118  	}
   119  
   120  	// sys_umtx_sleep will return EWOULDBLOCK (EAGAIN) when the timeout
   121  	// expires or EBUSY if the mutex value does not match.
   122  	ret := sys_umtx_sleep(addr, int32(val), timeout)
   123  	if ret >= 0 || ret == -_EINTR || ret == -_EAGAIN || ret == -_EBUSY {
   124  		return
   125  	}
   126  
   127  	print("umtx_sleep addr=", addr, " val=", val, " ret=", ret, "\n")
   128  	*(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
   129  }
   130  
   131  //go:nosplit
   132  func futexwakeup(addr *uint32, cnt uint32) {
   133  	ret := sys_umtx_wakeup(addr, int32(cnt))
   134  	if ret >= 0 {
   135  		return
   136  	}
   137  
   138  	systemstack(func() {
   139  		print("umtx_wake_addr=", addr, " ret=", ret, "\n")
   140  		*(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006
   141  	})
   142  }
   143  
   144  func lwp_start(uintptr)
   145  
   146  // May run with m.p==nil, so write barriers are not allowed.
   147  //
   148  //go:nowritebarrier
   149  func newosproc(mp *m) {
   150  	stk := unsafe.Pointer(mp.g0.stack.hi)
   151  	if false {
   152  		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " lwp_start=", abi.FuncPCABI0(lwp_start), " id=", mp.id, " ostk=", &mp, "\n")
   153  	}
   154  
   155  	var oset sigset
   156  	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   157  
   158  	params := lwpparams{
   159  		start_func: abi.FuncPCABI0(lwp_start),
   160  		arg:        unsafe.Pointer(mp),
   161  		stack:      uintptr(stk),
   162  		tid1:       nil, // minit will record tid
   163  		tid2:       nil,
   164  	}
   165  
   166  	// TODO: Check for error.
   167  	retryOnEAGAIN(func() int32 {
   168  		lwp_create(&params)
   169  		return 0
   170  	})
   171  	sigprocmask(_SIG_SETMASK, &oset, nil)
   172  }
   173  
   174  func osinit() {
   175  	ncpu = getncpu()
   176  	if physPageSize == 0 {
   177  		physPageSize = getPageSize()
   178  	}
   179  }
   180  
   181  var urandom_dev = []byte("/dev/urandom\x00")
   182  
   183  //go:nosplit
   184  func readRandom(r []byte) int {
   185  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   186  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   187  	closefd(fd)
   188  	return int(n)
   189  }
   190  
   191  func goenvs() {
   192  	goenvs_unix()
   193  }
   194  
   195  // Called to initialize a new m (including the bootstrap m).
   196  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   197  func mpreinit(mp *m) {
   198  	mp.gsignal = malg(32 * 1024)
   199  	mp.gsignal.m = mp
   200  }
   201  
   202  // Called to initialize a new m (including the bootstrap m).
   203  // Called on the new thread, cannot allocate memory.
   204  func minit() {
   205  	getg().m.procid = uint64(lwp_gettid())
   206  	minitSignals()
   207  }
   208  
   209  // Called from dropm to undo the effect of an minit.
   210  //
   211  //go:nosplit
   212  func unminit() {
   213  	unminitSignals()
   214  	getg().m.procid = 0
   215  }
   216  
   217  // Called from exitm, but not from drop, to undo the effect of thread-owned
   218  // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
   219  func mdestroy(mp *m) {
   220  }
   221  
   222  func sigtramp()
   223  
   224  type sigactiont struct {
   225  	sa_sigaction uintptr
   226  	sa_flags     int32
   227  	sa_mask      sigset
   228  }
   229  
   230  //go:nosplit
   231  //go:nowritebarrierrec
   232  func setsig(i uint32, fn uintptr) {
   233  	var sa sigactiont
   234  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
   235  	sa.sa_mask = sigset_all
   236  	if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go
   237  		fn = abi.FuncPCABI0(sigtramp)
   238  	}
   239  	sa.sa_sigaction = fn
   240  	sigaction(i, &sa, nil)
   241  }
   242  
   243  //go:nosplit
   244  //go:nowritebarrierrec
   245  func setsigstack(i uint32) {
   246  	throw("setsigstack")
   247  }
   248  
   249  //go:nosplit
   250  //go:nowritebarrierrec
   251  func getsig(i uint32) uintptr {
   252  	var sa sigactiont
   253  	sigaction(i, nil, &sa)
   254  	return sa.sa_sigaction
   255  }
   256  
   257  // setSignalstackSP sets the ss_sp field of a stackt.
   258  //
   259  //go:nosplit
   260  func setSignalstackSP(s *stackt, sp uintptr) {
   261  	s.ss_sp = sp
   262  }
   263  
   264  //go:nosplit
   265  //go:nowritebarrierrec
   266  func sigaddset(mask *sigset, i int) {
   267  	mask.__bits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
   268  }
   269  
   270  func sigdelset(mask *sigset, i int) {
   271  	mask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
   272  }
   273  
   274  //go:nosplit
   275  func (c *sigctxt) fixsigcode(sig uint32) {
   276  }
   277  
   278  func setProcessCPUProfiler(hz int32) {
   279  	setProcessCPUProfilerTimer(hz)
   280  }
   281  
   282  func setThreadCPUProfiler(hz int32) {
   283  	setThreadCPUProfilerHz(hz)
   284  }
   285  
   286  //go:nosplit
   287  func validSIGPROF(mp *m, c *sigctxt) bool {
   288  	return true
   289  }
   290  
   291  func sysargs(argc int32, argv **byte) {
   292  	n := argc + 1
   293  
   294  	// skip over argv, envp to get to auxv
   295  	for argv_index(argv, n) != nil {
   296  		n++
   297  	}
   298  
   299  	// skip NULL separator
   300  	n++
   301  
   302  	auxvp := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*goarch.PtrSize))
   303  	pairs := sysauxv(auxvp[:])
   304  	auxv = auxvp[: pairs*2 : pairs*2]
   305  }
   306  
   307  const (
   308  	_AT_NULL   = 0
   309  	_AT_PAGESZ = 6
   310  )
   311  
   312  func sysauxv(auxv []uintptr) (pairs int) {
   313  	var i int
   314  	for i = 0; auxv[i] != _AT_NULL; i += 2 {
   315  		tag, val := auxv[i], auxv[i+1]
   316  		switch tag {
   317  		case _AT_PAGESZ:
   318  			physPageSize = val
   319  		}
   320  	}
   321  	return i / 2
   322  }
   323  
   324  // raise sends a signal to the calling thread.
   325  //
   326  // It must be nosplit because it is used by the signal handler before
   327  // it definitely has a Go stack.
   328  //
   329  //go:nosplit
   330  func raise(sig uint32) {
   331  	lwp_kill(-1, lwp_gettid(), int(sig))
   332  }
   333  
   334  func signalM(mp *m, sig int) {
   335  	lwp_kill(-1, int32(mp.procid), sig)
   336  }
   337  
   338  // sigPerThreadSyscall is only used on linux, so we assign a bogus signal
   339  // number.
   340  const sigPerThreadSyscall = 1 << 31
   341  
   342  //go:nosplit
   343  func runPerThreadSyscall() {
   344  	throw("runPerThreadSyscall only valid on linux")
   345  }
   346  

View as plain text