github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/runtime/os_dragonfly.go (about)

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