github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/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  	lwp_create(&params)
   138  	sigprocmask(_SIG_SETMASK, &oset, nil)
   139  }
   140  
   141  func osinit() {
   142  	ncpu = getncpu()
   143  }
   144  
   145  var urandom_dev = []byte("/dev/urandom\x00")
   146  
   147  //go:nosplit
   148  func getRandomData(r []byte) {
   149  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   150  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   151  	closefd(fd)
   152  	extendRandom(r, int(n))
   153  }
   154  
   155  func goenvs() {
   156  	goenvs_unix()
   157  }
   158  
   159  // Called to initialize a new m (including the bootstrap m).
   160  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   161  func mpreinit(mp *m) {
   162  	mp.gsignal = malg(32 * 1024)
   163  	mp.gsignal.m = mp
   164  }
   165  
   166  //go:nosplit
   167  func msigsave(mp *m) {
   168  	sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
   169  }
   170  
   171  //go:nosplit
   172  func msigrestore(sigmask sigset) {
   173  	sigprocmask(_SIG_SETMASK, &sigmask, nil)
   174  }
   175  
   176  //go:nosplit
   177  func sigblock() {
   178  	sigprocmask(_SIG_SETMASK, &sigset_all, nil)
   179  }
   180  
   181  // Called to initialize a new m (including the bootstrap m).
   182  // Called on the new thread, cannot allocate memory.
   183  func minit() {
   184  	_g_ := getg()
   185  
   186  	// m.procid is a uint64, but lwp_start writes an int32. Fix it up.
   187  	_g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
   188  
   189  	// Initialize signal handling.
   190  
   191  	// On DragonFly a thread created by pthread_create inherits
   192  	// the signal stack of the creating thread. We always create
   193  	// a new signal stack here, to avoid having two Go threads
   194  	// using the same signal stack. This breaks the case of a
   195  	// thread created in C that calls sigaltstack and then calls a
   196  	// Go function, because we will lose track of the C code's
   197  	// sigaltstack, but it's the best we can do.
   198  	signalstack(&_g_.m.gsignal.stack)
   199  	_g_.m.newSigstack = true
   200  
   201  	// restore signal mask from m.sigmask and unblock essential signals
   202  	nmask := _g_.m.sigmask
   203  	for i := range sigtable {
   204  		if sigtable[i].flags&_SigUnblock != 0 {
   205  			nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
   206  		}
   207  	}
   208  	sigprocmask(_SIG_SETMASK, &nmask, nil)
   209  }
   210  
   211  // Called from dropm to undo the effect of an minit.
   212  //go:nosplit
   213  func unminit() {
   214  	if getg().m.newSigstack {
   215  		signalstack(nil)
   216  	}
   217  }
   218  
   219  func memlimit() uintptr {
   220  	/*
   221  		                TODO: Convert to Go when something actually uses the result.
   222  
   223  				Rlimit rl;
   224  				extern byte runtime·text[], runtime·end[];
   225  				uintptr used;
   226  
   227  				if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
   228  					return 0;
   229  				if(rl.rlim_cur >= 0x7fffffff)
   230  					return 0;
   231  
   232  				// Estimate our VM footprint excluding the heap.
   233  				// Not an exact science: use size of binary plus
   234  				// some room for thread stacks.
   235  				used = runtime·end - runtime·text + (64<<20);
   236  				if(used >= rl.rlim_cur)
   237  					return 0;
   238  
   239  				// If there's not at least 16 MB left, we're probably
   240  				// not going to be able to do much. Treat as no limit.
   241  				rl.rlim_cur -= used;
   242  				if(rl.rlim_cur < (16<<20))
   243  					return 0;
   244  
   245  				return rl.rlim_cur - used;
   246  	*/
   247  	return 0
   248  }
   249  
   250  func sigtramp()
   251  
   252  type sigactiont struct {
   253  	sa_sigaction uintptr
   254  	sa_flags     int32
   255  	sa_mask      sigset
   256  }
   257  
   258  //go:nosplit
   259  //go:nowritebarrierrec
   260  func setsig(i int32, fn uintptr, restart bool) {
   261  	var sa sigactiont
   262  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
   263  	if restart {
   264  		sa.sa_flags |= _SA_RESTART
   265  	}
   266  	sa.sa_mask = sigset_all
   267  	if fn == funcPC(sighandler) {
   268  		fn = funcPC(sigtramp)
   269  	}
   270  	sa.sa_sigaction = fn
   271  	sigaction(i, &sa, nil)
   272  }
   273  
   274  //go:nosplit
   275  //go:nowritebarrierrec
   276  func setsigstack(i int32) {
   277  	throw("setsigstack")
   278  }
   279  
   280  //go:nosplit
   281  //go:nowritebarrierrec
   282  func getsig(i int32) uintptr {
   283  	var sa sigactiont
   284  	sigaction(i, nil, &sa)
   285  	if sa.sa_sigaction == funcPC(sigtramp) {
   286  		return funcPC(sighandler)
   287  	}
   288  	return sa.sa_sigaction
   289  }
   290  
   291  //go:nosplit
   292  func signalstack(s *stack) {
   293  	var st sigaltstackt
   294  	if s == nil {
   295  		st.ss_flags = _SS_DISABLE
   296  	} else {
   297  		st.ss_sp = s.lo
   298  		st.ss_size = s.hi - s.lo
   299  		st.ss_flags = 0
   300  	}
   301  	sigaltstack(&st, nil)
   302  }
   303  
   304  //go:nosplit
   305  //go:nowritebarrierrec
   306  func updatesigmask(m sigmask) {
   307  	var mask sigset
   308  	copy(mask.__bits[:], m[:])
   309  	sigprocmask(_SIG_SETMASK, &mask, nil)
   310  }
   311  
   312  func unblocksig(sig int32) {
   313  	var mask sigset
   314  	mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
   315  	sigprocmask(_SIG_UNBLOCK, &mask, nil)
   316  }