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