github.com/euank/go@v0.0.0-20160829210321-495514729181/src/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 "unsafe"
     8  
     9  const (
    10  	_NSIG        = 33
    11  	_SI_USER     = 0
    12  	_SS_DISABLE  = 4
    13  	_RLIMIT_AS   = 10
    14  	_SIG_BLOCK   = 1
    15  	_SIG_UNBLOCK = 2
    16  	_SIG_SETMASK = 3
    17  )
    18  
    19  type mOS struct{}
    20  
    21  //go:noescape
    22  func lwp_create(param *lwpparams) int32
    23  
    24  //go:noescape
    25  func sigaltstack(new, old *sigaltstackt)
    26  
    27  //go:noescape
    28  func sigaction(sig int32, new, old *sigactiont)
    29  
    30  //go:noescape
    31  func sigprocmask(how int32, new, old *sigset)
    32  
    33  //go:noescape
    34  func setitimer(mode int32, new, old *itimerval)
    35  
    36  //go:noescape
    37  func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
    38  
    39  //go:noescape
    40  func getrlimit(kind int32, limit unsafe.Pointer) int32
    41  
    42  func raise(sig int32)
    43  func raiseproc(sig int32)
    44  
    45  //go:noescape
    46  func sys_umtx_sleep(addr *uint32, val, timeout int32) int32
    47  
    48  //go:noescape
    49  func sys_umtx_wakeup(addr *uint32, val int32) int32
    50  
    51  func osyield()
    52  
    53  const stackSystem = 0
    54  
    55  // From DragonFly's <sys/sysctl.h>
    56  const (
    57  	_CTL_HW  = 6
    58  	_HW_NCPU = 3
    59  )
    60  
    61  var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
    62  
    63  func getncpu() int32 {
    64  	mib := [2]uint32{_CTL_HW, _HW_NCPU}
    65  	out := uint32(0)
    66  	nout := unsafe.Sizeof(out)
    67  	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
    68  	if ret >= 0 {
    69  		return int32(out)
    70  	}
    71  	return 1
    72  }
    73  
    74  //go:nosplit
    75  func futexsleep(addr *uint32, val uint32, ns int64) {
    76  	systemstack(func() {
    77  		futexsleep1(addr, val, ns)
    78  	})
    79  }
    80  
    81  func futexsleep1(addr *uint32, val uint32, ns int64) {
    82  	var timeout int32
    83  	if ns >= 0 {
    84  		// The timeout is specified in microseconds - ensure that we
    85  		// do not end up dividing to zero, which would put us to sleep
    86  		// indefinitely...
    87  		timeout = timediv(ns, 1000, nil)
    88  		if timeout == 0 {
    89  			timeout = 1
    90  		}
    91  	}
    92  
    93  	// sys_umtx_sleep will return EWOULDBLOCK (EAGAIN) when the timeout
    94  	// expires or EBUSY if the mutex value does not match.
    95  	ret := sys_umtx_sleep(addr, int32(val), timeout)
    96  	if ret >= 0 || ret == -_EINTR || ret == -_EAGAIN || ret == -_EBUSY {
    97  		return
    98  	}
    99  
   100  	print("umtx_sleep addr=", addr, " val=", val, " ret=", ret, "\n")
   101  	*(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
   102  }
   103  
   104  //go:nosplit
   105  func futexwakeup(addr *uint32, cnt uint32) {
   106  	ret := sys_umtx_wakeup(addr, int32(cnt))
   107  	if ret >= 0 {
   108  		return
   109  	}
   110  
   111  	systemstack(func() {
   112  		print("umtx_wake_addr=", addr, " ret=", ret, "\n")
   113  		*(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006
   114  	})
   115  }
   116  
   117  func lwp_start(uintptr)
   118  
   119  // May run with m.p==nil, so write barriers are not allowed.
   120  //go:nowritebarrier
   121  func newosproc(mp *m, stk unsafe.Pointer) {
   122  	if false {
   123  		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " lwp_start=", funcPC(lwp_start), " id=", mp.id, " ostk=", &mp, "\n")
   124  	}
   125  
   126  	var oset sigset
   127  	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   128  
   129  	params := lwpparams{
   130  		start_func: funcPC(lwp_start),
   131  		arg:        unsafe.Pointer(mp),
   132  		stack:      uintptr(stk),
   133  		tid1:       unsafe.Pointer(&mp.procid),
   134  		tid2:       nil,
   135  	}
   136  
   137  	// TODO: Check for error.
   138  	lwp_create(&params)
   139  	sigprocmask(_SIG_SETMASK, &oset, nil)
   140  }
   141  
   142  func osinit() {
   143  	ncpu = getncpu()
   144  }
   145  
   146  var urandom_dev = []byte("/dev/urandom\x00")
   147  
   148  //go:nosplit
   149  func getRandomData(r []byte) {
   150  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   151  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   152  	closefd(fd)
   153  	extendRandom(r, int(n))
   154  }
   155  
   156  func goenvs() {
   157  	goenvs_unix()
   158  }
   159  
   160  // Called to initialize a new m (including the bootstrap m).
   161  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   162  func mpreinit(mp *m) {
   163  	mp.gsignal = malg(32 * 1024)
   164  	mp.gsignal.m = mp
   165  }
   166  
   167  //go:nosplit
   168  func msigsave(mp *m) {
   169  	sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
   170  }
   171  
   172  //go:nosplit
   173  func msigrestore(sigmask sigset) {
   174  	sigprocmask(_SIG_SETMASK, &sigmask, nil)
   175  }
   176  
   177  //go:nosplit
   178  func sigblock() {
   179  	sigprocmask(_SIG_SETMASK, &sigset_all, nil)
   180  }
   181  
   182  // Called to initialize a new m (including the bootstrap m).
   183  // Called on the new thread, cannot allocate memory.
   184  func minit() {
   185  	_g_ := getg()
   186  
   187  	// m.procid is a uint64, but lwp_start writes an int32. Fix it up.
   188  	_g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
   189  
   190  	// Initialize signal handling.
   191  
   192  	// On DragonFly a thread created by pthread_create inherits
   193  	// the signal stack of the creating thread. We always create
   194  	// a new signal stack here, to avoid having two Go threads
   195  	// using the same signal stack. This breaks the case of a
   196  	// thread created in C that calls sigaltstack and then calls a
   197  	// Go function, because we will lose track of the C code's
   198  	// sigaltstack, but it's the best we can do.
   199  	signalstack(&_g_.m.gsignal.stack)
   200  	_g_.m.newSigstack = true
   201  
   202  	// restore signal mask from m.sigmask and unblock essential signals
   203  	nmask := _g_.m.sigmask
   204  	for i := range sigtable {
   205  		if sigtable[i].flags&_SigUnblock != 0 {
   206  			nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
   207  		}
   208  	}
   209  	sigprocmask(_SIG_SETMASK, &nmask, nil)
   210  }
   211  
   212  // Called from dropm to undo the effect of an minit.
   213  //go:nosplit
   214  func unminit() {
   215  	if getg().m.newSigstack {
   216  		signalstack(nil)
   217  	}
   218  }
   219  
   220  func memlimit() uintptr {
   221  	/*
   222  		                TODO: Convert to Go when something actually uses the result.
   223  
   224  				Rlimit rl;
   225  				extern byte runtime·text[], runtime·end[];
   226  				uintptr used;
   227  
   228  				if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
   229  					return 0;
   230  				if(rl.rlim_cur >= 0x7fffffff)
   231  					return 0;
   232  
   233  				// Estimate our VM footprint excluding the heap.
   234  				// Not an exact science: use size of binary plus
   235  				// some room for thread stacks.
   236  				used = runtime·end - runtime·text + (64<<20);
   237  				if(used >= rl.rlim_cur)
   238  					return 0;
   239  
   240  				// If there's not at least 16 MB left, we're probably
   241  				// not going to be able to do much. Treat as no limit.
   242  				rl.rlim_cur -= used;
   243  				if(rl.rlim_cur < (16<<20))
   244  					return 0;
   245  
   246  				return rl.rlim_cur - used;
   247  	*/
   248  	return 0
   249  }
   250  
   251  func sigtramp()
   252  
   253  type sigactiont struct {
   254  	sa_sigaction uintptr
   255  	sa_flags     int32
   256  	sa_mask      sigset
   257  }
   258  
   259  //go:nosplit
   260  //go:nowritebarrierrec
   261  func setsig(i int32, fn uintptr, restart bool) {
   262  	var sa sigactiont
   263  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
   264  	if restart {
   265  		sa.sa_flags |= _SA_RESTART
   266  	}
   267  	sa.sa_mask = sigset_all
   268  	if fn == funcPC(sighandler) {
   269  		fn = funcPC(sigtramp)
   270  	}
   271  	sa.sa_sigaction = fn
   272  	sigaction(i, &sa, nil)
   273  }
   274  
   275  //go:nosplit
   276  //go:nowritebarrierrec
   277  func setsigstack(i int32) {
   278  	throw("setsigstack")
   279  }
   280  
   281  //go:nosplit
   282  //go:nowritebarrierrec
   283  func getsig(i int32) uintptr {
   284  	var sa sigactiont
   285  	sigaction(i, nil, &sa)
   286  	if sa.sa_sigaction == funcPC(sigtramp) {
   287  		return funcPC(sighandler)
   288  	}
   289  	return sa.sa_sigaction
   290  }
   291  
   292  //go:nosplit
   293  func signalstack(s *stack) {
   294  	var st sigaltstackt
   295  	if s == nil {
   296  		st.ss_flags = _SS_DISABLE
   297  	} else {
   298  		st.ss_sp = s.lo
   299  		st.ss_size = s.hi - s.lo
   300  		st.ss_flags = 0
   301  	}
   302  	sigaltstack(&st, nil)
   303  }
   304  
   305  //go:nosplit
   306  //go:nowritebarrierrec
   307  func updatesigmask(m sigmask) {
   308  	var mask sigset
   309  	copy(mask.__bits[:], m[:])
   310  	sigprocmask(_SIG_SETMASK, &mask, nil)
   311  }
   312  
   313  func unblocksig(sig int32) {
   314  	var mask sigset
   315  	mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
   316  	sigprocmask(_SIG_UNBLOCK, &mask, nil)
   317  }