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