Black Lives Matter. Support the Equal Justice Initiative.

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

View as plain text