github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/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  		gothrow("runtime.newosproc")
   166  	}
   167  }
   168  
   169  func osinit() {
   170  	ncpu = getncpu()
   171  }
   172  
   173  var urandom_data [_HashRandomBytes]byte
   174  var urandom_dev = []byte("/dev/urandom\x00")
   175  
   176  //go:nosplit
   177  func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) {
   178  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   179  	if read(fd, unsafe.Pointer(&urandom_data), _HashRandomBytes) == _HashRandomBytes {
   180  		*rnd = unsafe.Pointer(&urandom_data[0])
   181  		*rnd_len = _HashRandomBytes
   182  	} else {
   183  		*rnd = nil
   184  		*rnd_len = 0
   185  	}
   186  	close(fd)
   187  }
   188  
   189  func goenvs() {
   190  	goenvs_unix()
   191  }
   192  
   193  // Called to initialize a new m (including the bootstrap m).
   194  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   195  func mpreinit(mp *m) {
   196  	mp.gsignal = malg(32 * 1024)
   197  	mp.gsignal.m = mp
   198  }
   199  
   200  // Called to initialize a new m (including the bootstrap m).
   201  // Called on the new thread, can not allocate memory.
   202  func minit() {
   203  	_g_ := getg()
   204  	_g_.m.procid = uint64(lwp_self())
   205  
   206  	// Initialize signal handling
   207  	signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
   208  	sigprocmask(_SIG_SETMASK, &sigset_none, nil)
   209  }
   210  
   211  // Called from dropm to undo the effect of an minit.
   212  func unminit() {
   213  	signalstack(nil, 0)
   214  }
   215  
   216  func memlimit() uintptr {
   217  	return 0
   218  }
   219  
   220  func sigtramp()
   221  
   222  type sigactiont struct {
   223  	sa_sigaction uintptr
   224  	sa_mask      sigset
   225  	sa_flags     int32
   226  }
   227  
   228  func setsig(i int32, fn uintptr, restart bool) {
   229  	var sa sigactiont
   230  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
   231  	if restart {
   232  		sa.sa_flags |= _SA_RESTART
   233  	}
   234  	sa.sa_mask = sigset_all
   235  	if fn == funcPC(sighandler) {
   236  		fn = funcPC(sigtramp)
   237  	}
   238  	sa.sa_sigaction = fn
   239  	sigaction(i, &sa, nil)
   240  }
   241  
   242  func getsig(i int32) uintptr {
   243  	var sa sigactiont
   244  	sigaction(i, nil, &sa)
   245  	if sa.sa_sigaction == funcPC(sigtramp) {
   246  		return funcPC(sighandler)
   247  	}
   248  	return sa.sa_sigaction
   249  }
   250  
   251  func signalstack(p *byte, n int32) {
   252  	var st sigaltstackt
   253  
   254  	st.ss_sp = uintptr(unsafe.Pointer(p))
   255  	st.ss_size = uintptr(n)
   256  	st.ss_flags = 0
   257  	if p == nil {
   258  		st.ss_flags = _SS_DISABLE
   259  	}
   260  	sigaltstack(&st, nil)
   261  }
   262  
   263  func unblocksignals() {
   264  	sigprocmask(_SIG_SETMASK, &sigset_none, nil)
   265  }