...

Source file src/runtime/os_netbsd.go

     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		"runtime/internal/atomic"
     9		"runtime/internal/sys"
    10		"unsafe"
    11	)
    12	
    13	const (
    14		_SS_DISABLE  = 4
    15		_SIG_BLOCK   = 1
    16		_SIG_UNBLOCK = 2
    17		_SIG_SETMASK = 3
    18		_NSIG        = 33
    19		_SI_USER     = 0
    20	
    21		// From NetBSD's <sys/ucontext.h>
    22		_UC_SIGMASK = 0x01
    23		_UC_CPU     = 0x04
    24	
    25		// From <sys/lwp.h>
    26		_LWP_DETACHED = 0x00000040
    27	
    28		_EAGAIN = 35
    29	)
    30	
    31	type mOS struct {
    32		waitsemacount uint32
    33	}
    34	
    35	//go:noescape
    36	func setitimer(mode int32, new, old *itimerval)
    37	
    38	//go:noescape
    39	func sigaction(sig uint32, new, old *sigactiont)
    40	
    41	//go:noescape
    42	func sigaltstack(new, old *stackt)
    43	
    44	//go:noescape
    45	func sigprocmask(how int32, new, old *sigset)
    46	
    47	//go:noescape
    48	func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
    49	
    50	func lwp_tramp()
    51	
    52	func raise(sig uint32)
    53	func raiseproc(sig uint32)
    54	
    55	//go:noescape
    56	func getcontext(ctxt unsafe.Pointer)
    57	
    58	//go:noescape
    59	func lwp_create(ctxt unsafe.Pointer, flags uintptr, lwpid unsafe.Pointer) int32
    60	
    61	//go:noescape
    62	func lwp_park(clockid, flags int32, ts *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32
    63	
    64	//go:noescape
    65	func lwp_unpark(lwp int32, hint unsafe.Pointer) int32
    66	
    67	func lwp_self() int32
    68	
    69	func osyield()
    70	
    71	func kqueue() int32
    72	
    73	//go:noescape
    74	func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
    75	func closeonexec(fd int32)
    76	
    77	const (
    78		_ESRCH     = 3
    79		_ETIMEDOUT = 60
    80	
    81		// From NetBSD's <sys/time.h>
    82		_CLOCK_REALTIME  = 0
    83		_CLOCK_VIRTUAL   = 1
    84		_CLOCK_PROF      = 2
    85		_CLOCK_MONOTONIC = 3
    86	
    87		_TIMER_RELTIME = 0
    88		_TIMER_ABSTIME = 1
    89	)
    90	
    91	var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
    92	
    93	// From NetBSD's <sys/sysctl.h>
    94	const (
    95		_CTL_HW      = 6
    96		_HW_NCPU     = 3
    97		_HW_PAGESIZE = 7
    98	)
    99	
   100	func getncpu() int32 {
   101		mib := [2]uint32{_CTL_HW, _HW_NCPU}
   102		out := uint32(0)
   103		nout := unsafe.Sizeof(out)
   104		ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
   105		if ret >= 0 {
   106			return int32(out)
   107		}
   108		return 1
   109	}
   110	
   111	func getPageSize() uintptr {
   112		mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
   113		out := uint32(0)
   114		nout := unsafe.Sizeof(out)
   115		ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
   116		if ret >= 0 {
   117			return uintptr(out)
   118		}
   119		return 0
   120	}
   121	
   122	//go:nosplit
   123	func semacreate(mp *m) {
   124	}
   125	
   126	//go:nosplit
   127	func semasleep(ns int64) int32 {
   128		_g_ := getg()
   129		var deadline int64
   130		if ns >= 0 {
   131			deadline = nanotime() + ns
   132		}
   133	
   134		for {
   135			v := atomic.Load(&_g_.m.waitsemacount)
   136			if v > 0 {
   137				if atomic.Cas(&_g_.m.waitsemacount, v, v-1) {
   138					return 0 // semaphore acquired
   139				}
   140				continue
   141			}
   142	
   143			// Sleep until unparked by semawakeup or timeout.
   144			var tsp *timespec
   145			var ts timespec
   146			if ns >= 0 {
   147				wait := deadline - nanotime()
   148				if wait <= 0 {
   149					return -1
   150				}
   151				ts.setNsec(wait)
   152				tsp = &ts
   153			}
   154			ret := lwp_park(_CLOCK_MONOTONIC, _TIMER_RELTIME, tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil)
   155			if ret == _ETIMEDOUT {
   156				return -1
   157			}
   158		}
   159	}
   160	
   161	//go:nosplit
   162	func semawakeup(mp *m) {
   163		atomic.Xadd(&mp.waitsemacount, 1)
   164		// From NetBSD's _lwp_unpark(2) manual:
   165		// "If the target LWP is not currently waiting, it will return
   166		// immediately upon the next call to _lwp_park()."
   167		ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.waitsemacount))
   168		if ret != 0 && ret != _ESRCH {
   169			// semawakeup can be called on signal stack.
   170			systemstack(func() {
   171				print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
   172			})
   173		}
   174	}
   175	
   176	// May run with m.p==nil, so write barriers are not allowed.
   177	//go:nowritebarrier
   178	func newosproc(mp *m) {
   179		stk := unsafe.Pointer(mp.g0.stack.hi)
   180		if false {
   181			print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n")
   182		}
   183	
   184		var uc ucontextt
   185		getcontext(unsafe.Pointer(&uc))
   186	
   187		// _UC_SIGMASK does not seem to work here.
   188		// It would be nice if _UC_SIGMASK and _UC_STACK
   189		// worked so that we could do all the work setting
   190		// the sigmask and the stack here, instead of setting
   191		// the mask here and the stack in netbsdMstart.
   192		// For now do the blocking manually.
   193		uc.uc_flags = _UC_SIGMASK | _UC_CPU
   194		uc.uc_link = nil
   195		uc.uc_sigmask = sigset_all
   196	
   197		var oset sigset
   198		sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   199	
   200		lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, funcPC(netbsdMstart))
   201	
   202		ret := lwp_create(unsafe.Pointer(&uc), _LWP_DETACHED, unsafe.Pointer(&mp.procid))
   203		sigprocmask(_SIG_SETMASK, &oset, nil)
   204		if ret < 0 {
   205			print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
   206			if ret == -_EAGAIN {
   207				println("runtime: may need to increase max user processes (ulimit -p)")
   208			}
   209			throw("runtime.newosproc")
   210		}
   211	}
   212	
   213	// netbsdMStart is the function call that starts executing a newly
   214	// created thread. On NetBSD, a new thread inherits the signal stack
   215	// of the creating thread. That confuses minit, so we remove that
   216	// signal stack here before calling the regular mstart. It's a bit
   217	// baroque to remove a signal stack here only to add one in minit, but
   218	// it's a simple change that keeps NetBSD working like other OS's.
   219	// At this point all signals are blocked, so there is no race.
   220	//go:nosplit
   221	func netbsdMstart() {
   222		st := stackt{ss_flags: _SS_DISABLE}
   223		sigaltstack(&st, nil)
   224		mstart()
   225	}
   226	
   227	func osinit() {
   228		ncpu = getncpu()
   229		if physPageSize == 0 {
   230			physPageSize = getPageSize()
   231		}
   232	}
   233	
   234	var urandom_dev = []byte("/dev/urandom\x00")
   235	
   236	//go:nosplit
   237	func getRandomData(r []byte) {
   238		fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   239		n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   240		closefd(fd)
   241		extendRandom(r, int(n))
   242	}
   243	
   244	func goenvs() {
   245		goenvs_unix()
   246	}
   247	
   248	// Called to initialize a new m (including the bootstrap m).
   249	// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   250	func mpreinit(mp *m) {
   251		mp.gsignal = malg(32 * 1024)
   252		mp.gsignal.m = mp
   253	}
   254	
   255	// Called to initialize a new m (including the bootstrap m).
   256	// Called on the new thread, cannot allocate memory.
   257	func minit() {
   258		_g_ := getg()
   259		_g_.m.procid = uint64(lwp_self())
   260	
   261		// On NetBSD a thread created by pthread_create inherits the
   262		// signal stack of the creating thread. We always create a
   263		// new signal stack here, to avoid having two Go threads using
   264		// the same signal stack. This breaks the case of a thread
   265		// created in C that calls sigaltstack and then calls a Go
   266		// function, because we will lose track of the C code's
   267		// sigaltstack, but it's the best we can do.
   268		signalstack(&_g_.m.gsignal.stack)
   269		_g_.m.newSigstack = true
   270	
   271		minitSignalMask()
   272	}
   273	
   274	// Called from dropm to undo the effect of an minit.
   275	//go:nosplit
   276	func unminit() {
   277		unminitSignals()
   278	}
   279	
   280	func sigtramp()
   281	
   282	type sigactiont struct {
   283		sa_sigaction uintptr
   284		sa_mask      sigset
   285		sa_flags     int32
   286	}
   287	
   288	//go:nosplit
   289	//go:nowritebarrierrec
   290	func setsig(i uint32, fn uintptr) {
   291		var sa sigactiont
   292		sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
   293		sa.sa_mask = sigset_all
   294		if fn == funcPC(sighandler) {
   295			fn = funcPC(sigtramp)
   296		}
   297		sa.sa_sigaction = fn
   298		sigaction(i, &sa, nil)
   299	}
   300	
   301	//go:nosplit
   302	//go:nowritebarrierrec
   303	func setsigstack(i uint32) {
   304		throw("setsigstack")
   305	}
   306	
   307	//go:nosplit
   308	//go:nowritebarrierrec
   309	func getsig(i uint32) uintptr {
   310		var sa sigactiont
   311		sigaction(i, nil, &sa)
   312		return sa.sa_sigaction
   313	}
   314	
   315	// setSignaltstackSP sets the ss_sp field of a stackt.
   316	//go:nosplit
   317	func setSignalstackSP(s *stackt, sp uintptr) {
   318		s.ss_sp = sp
   319	}
   320	
   321	//go:nosplit
   322	//go:nowritebarrierrec
   323	func sigaddset(mask *sigset, i int) {
   324		mask.__bits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
   325	}
   326	
   327	func sigdelset(mask *sigset, i int) {
   328		mask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
   329	}
   330	
   331	//go:nosplit
   332	func (c *sigctxt) fixsigcode(sig uint32) {
   333	}
   334	
   335	func sysargs(argc int32, argv **byte) {
   336		n := argc + 1
   337	
   338		// skip over argv, envp to get to auxv
   339		for argv_index(argv, n) != nil {
   340			n++
   341		}
   342	
   343		// skip NULL separator
   344		n++
   345	
   346		// now argv+n is auxv
   347		auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize))
   348		sysauxv(auxv[:])
   349	}
   350	
   351	const (
   352		_AT_NULL   = 0 // Terminates the vector
   353		_AT_PAGESZ = 6 // Page size in bytes
   354	)
   355	
   356	func sysauxv(auxv []uintptr) {
   357		for i := 0; auxv[i] != _AT_NULL; i += 2 {
   358			tag, val := auxv[i], auxv[i+1]
   359			switch tag {
   360			case _AT_PAGESZ:
   361				physPageSize = val
   362			}
   363		}
   364	}
   365	

View as plain text