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