github.com/reiver/go@v0.0.0-20150109200633-1d0c7792f172/src/runtime/os1_netbsd.go (about)

     1  // Copyright 2011 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  	_ESRCH   = 3
    11  	_ENOTSUP = 91
    12  
    13  	// From NetBSD's <sys/time.h>
    14  	_CLOCK_REALTIME  = 0
    15  	_CLOCK_VIRTUAL   = 1
    16  	_CLOCK_PROF      = 2
    17  	_CLOCK_MONOTONIC = 3
    18  )
    19  
    20  var sigset_none = sigset{}
    21  var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
    22  
    23  // From NetBSD's <sys/sysctl.h>
    24  const (
    25  	_CTL_HW  = 6
    26  	_HW_NCPU = 3
    27  )
    28  
    29  func getncpu() int32 {
    30  	mib := [2]uint32{_CTL_HW, _HW_NCPU}
    31  	out := uint32(0)
    32  	nout := unsafe.Sizeof(out)
    33  	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
    34  	if ret >= 0 {
    35  		return int32(out)
    36  	}
    37  	return 1
    38  }
    39  
    40  //go:nosplit
    41  func semacreate() uintptr {
    42  	return 1
    43  }
    44  
    45  //go:nosplit
    46  func semasleep(ns int64) int32 {
    47  	_g_ := getg()
    48  
    49  	// spin-mutex lock
    50  	for {
    51  		if xchg(&_g_.m.waitsemalock, 1) == 0 {
    52  			break
    53  		}
    54  		osyield()
    55  	}
    56  
    57  	for {
    58  		// lock held
    59  		if _g_.m.waitsemacount == 0 {
    60  			// sleep until semaphore != 0 or timeout.
    61  			// thrsleep unlocks m.waitsemalock.
    62  			if ns < 0 {
    63  				// TODO(jsing) - potential deadlock!
    64  				//
    65  				// There is a potential deadlock here since we
    66  				// have to release the waitsemalock mutex
    67  				// before we call lwp_park() to suspend the
    68  				// thread. This allows another thread to
    69  				// release the lock and call lwp_unpark()
    70  				// before the thread is actually suspended.
    71  				// If this occurs the current thread will end
    72  				// up sleeping indefinitely. Unfortunately
    73  				// the NetBSD kernel does not appear to provide
    74  				// a mechanism for unlocking the userspace
    75  				// mutex once the thread is actually parked.
    76  				atomicstore(&_g_.m.waitsemalock, 0)
    77  				lwp_park(nil, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil)
    78  			} else {
    79  				var ts timespec
    80  				var nsec int32
    81  				ns += nanotime()
    82  				ts.set_sec(timediv(ns, 1000000000, &nsec))
    83  				ts.set_nsec(nsec)
    84  				// TODO(jsing) - potential deadlock!
    85  				// See above for details.
    86  				atomicstore(&_g_.m.waitsemalock, 0)
    87  				lwp_park(&ts, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil)
    88  			}
    89  			// reacquire lock
    90  			for {
    91  				if xchg(&_g_.m.waitsemalock, 1) == 0 {
    92  					break
    93  				}
    94  				osyield()
    95  			}
    96  		}
    97  
    98  		// lock held (again)
    99  		if _g_.m.waitsemacount != 0 {
   100  			// semaphore is available.
   101  			_g_.m.waitsemacount--
   102  			// spin-mutex unlock
   103  			atomicstore(&_g_.m.waitsemalock, 0)
   104  			return 0
   105  		}
   106  
   107  		// semaphore not available.
   108  		// if there is a timeout, stop now.
   109  		// otherwise keep trying.
   110  		if ns >= 0 {
   111  			break
   112  		}
   113  	}
   114  
   115  	// lock held but giving up
   116  	// spin-mutex unlock
   117  	atomicstore(&_g_.m.waitsemalock, 0)
   118  	return -1
   119  }
   120  
   121  //go:nosplit
   122  func semawakeup(mp *m) {
   123  	// spin-mutex lock
   124  	for {
   125  		if xchg(&mp.waitsemalock, 1) == 0 {
   126  			break
   127  		}
   128  		osyield()
   129  	}
   130  
   131  	mp.waitsemacount++
   132  	// TODO(jsing) - potential deadlock, see semasleep() for details.
   133  	// Confirm that LWP is parked before unparking...
   134  	ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.waitsemacount))
   135  	if ret != 0 && ret != _ESRCH {
   136  		// semawakeup can be called on signal stack.
   137  		systemstack(func() {
   138  			print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
   139  		})
   140  	}
   141  
   142  	// spin-mutex unlock
   143  	atomicstore(&mp.waitsemalock, 0)
   144  }
   145  
   146  func newosproc(mp *m, stk unsafe.Pointer) {
   147  	if false {
   148  		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int32(mp.tls[0]), " ostk=", &mp, "\n")
   149  	}
   150  
   151  	mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
   152  
   153  	var uc ucontextt
   154  	getcontext(unsafe.Pointer(&uc))
   155  
   156  	uc.uc_flags = _UC_SIGMASK | _UC_CPU
   157  	uc.uc_link = nil
   158  	uc.uc_sigmask = sigset_all
   159  
   160  	lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, funcPC(mstart))
   161  
   162  	ret := lwp_create(unsafe.Pointer(&uc), 0, unsafe.Pointer(&mp.procid))
   163  	if ret < 0 {
   164  		print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
   165  		throw("runtime.newosproc")
   166  	}
   167  }
   168  
   169  func osinit() {
   170  	ncpu = getncpu()
   171  }
   172  
   173  var urandom_dev = []byte("/dev/urandom\x00")
   174  
   175  //go:nosplit
   176  func getRandomData(r []byte) {
   177  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   178  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   179  	close(fd)
   180  	extendRandom(r, int(n))
   181  }
   182  
   183  func goenvs() {
   184  	goenvs_unix()
   185  }
   186  
   187  // Called to initialize a new m (including the bootstrap m).
   188  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   189  func mpreinit(mp *m) {
   190  	mp.gsignal = malg(32 * 1024)
   191  	mp.gsignal.m = mp
   192  }
   193  
   194  // Called to initialize a new m (including the bootstrap m).
   195  // Called on the new thread, can not allocate memory.
   196  func minit() {
   197  	_g_ := getg()
   198  	_g_.m.procid = uint64(lwp_self())
   199  
   200  	// Initialize signal handling
   201  	signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
   202  	sigprocmask(_SIG_SETMASK, &sigset_none, nil)
   203  }
   204  
   205  // Called from dropm to undo the effect of an minit.
   206  func unminit() {
   207  	signalstack(nil, 0)
   208  }
   209  
   210  func memlimit() uintptr {
   211  	return 0
   212  }
   213  
   214  func sigtramp()
   215  
   216  type sigactiont struct {
   217  	sa_sigaction uintptr
   218  	sa_mask      sigset
   219  	sa_flags     int32
   220  }
   221  
   222  func setsig(i int32, fn uintptr, restart bool) {
   223  	var sa sigactiont
   224  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
   225  	if restart {
   226  		sa.sa_flags |= _SA_RESTART
   227  	}
   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  func setsigstack(i int32) {
   237  	throw("setsigstack")
   238  }
   239  
   240  func getsig(i int32) uintptr {
   241  	var sa sigactiont
   242  	sigaction(i, nil, &sa)
   243  	if sa.sa_sigaction == funcPC(sigtramp) {
   244  		return funcPC(sighandler)
   245  	}
   246  	return sa.sa_sigaction
   247  }
   248  
   249  func signalstack(p *byte, n int32) {
   250  	var st sigaltstackt
   251  
   252  	st.ss_sp = uintptr(unsafe.Pointer(p))
   253  	st.ss_size = uintptr(n)
   254  	st.ss_flags = 0
   255  	if p == nil {
   256  		st.ss_flags = _SS_DISABLE
   257  	}
   258  	sigaltstack(&st, nil)
   259  }
   260  
   261  func unblocksignals() {
   262  	sigprocmask(_SIG_SETMASK, &sigset_none, nil)
   263  }