1// Copyright 2009 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	"unsafe"
10)
11
12type mOS struct {
13	initialized bool
14	mutex       pthreadmutex
15	cond        pthreadcond
16	count       int
17}
18
19func unimplemented(name string) {
20	println(name, "not implemented")
21	*(*int)(unsafe.Pointer(uintptr(1231))) = 1231
22}
23
24//go:nosplit
25func semacreate(mp *m) {
26	if mp.initialized {
27		return
28	}
29	mp.initialized = true
30	if err := pthread_mutex_init(&mp.mutex, nil); err != 0 {
31		throw("pthread_mutex_init")
32	}
33	if err := pthread_cond_init(&mp.cond, nil); err != 0 {
34		throw("pthread_cond_init")
35	}
36}
37
38//go:nosplit
39func semasleep(ns int64) int32 {
40	var start int64
41	if ns >= 0 {
42		start = nanotime()
43	}
44	g := getg()
45	mp := g.m
46	if g == mp.gsignal {
47		// sema sleep/wakeup are implemented with pthreads, which are not async-signal-safe on Darwin.
48		throw("semasleep on Darwin signal stack")
49	}
50	pthread_mutex_lock(&mp.mutex)
51	for {
52		if mp.count > 0 {
53			mp.count--
54			pthread_mutex_unlock(&mp.mutex)
55			return 0
56		}
57		if ns >= 0 {
58			spent := nanotime() - start
59			if spent >= ns {
60				pthread_mutex_unlock(&mp.mutex)
61				return -1
62			}
63			var t timespec
64			t.setNsec(ns - spent)
65			err := pthread_cond_timedwait_relative_np(&mp.cond, &mp.mutex, &t)
66			if err == _ETIMEDOUT {
67				pthread_mutex_unlock(&mp.mutex)
68				return -1
69			}
70		} else {
71			pthread_cond_wait(&mp.cond, &mp.mutex)
72		}
73	}
74}
75
76//go:nosplit
77func semawakeup(mp *m) {
78	if g := getg(); g == g.m.gsignal {
79		throw("semawakeup on Darwin signal stack")
80	}
81	pthread_mutex_lock(&mp.mutex)
82	mp.count++
83	if mp.count > 0 {
84		pthread_cond_signal(&mp.cond)
85	}
86	pthread_mutex_unlock(&mp.mutex)
87}
88
89// The read and write file descriptors used by the sigNote functions.
90var sigNoteRead, sigNoteWrite int32
91
92// sigNoteSetup initializes a single, there-can-only-be-one, async-signal-safe note.
93//
94// The current implementation of notes on Darwin is not async-signal-safe,
95// because the functions pthread_mutex_lock, pthread_cond_signal, and
96// pthread_mutex_unlock, called by semawakeup, are not async-signal-safe.
97// There is only one case where we need to wake up a note from a signal
98// handler: the sigsend function. The signal handler code does not require
99// all the features of notes: it does not need to do a timed wait.
100// This is a separate implementation of notes, based on a pipe, that does
101// not support timed waits but is async-signal-safe.
102func sigNoteSetup(*note) {
103	if sigNoteRead != 0 || sigNoteWrite != 0 {
104		// Generalizing this would require avoiding the pipe-fork-closeonexec race, which entangles syscall.
105		throw("duplicate sigNoteSetup")
106	}
107	var errno int32
108	sigNoteRead, sigNoteWrite, errno = pipe()
109	if errno != 0 {
110		throw("pipe failed")
111	}
112	closeonexec(sigNoteRead)
113	closeonexec(sigNoteWrite)
114
115	// Make the write end of the pipe non-blocking, so that if the pipe
116	// buffer is somehow full we will not block in the signal handler.
117	// Leave the read end of the pipe blocking so that we will block
118	// in sigNoteSleep.
119	setNonblock(sigNoteWrite)
120}
121
122// sigNoteWakeup wakes up a thread sleeping on a note created by sigNoteSetup.
123func sigNoteWakeup(*note) {
124	var b byte
125	write(uintptr(sigNoteWrite), unsafe.Pointer(&b), 1)
126}
127
128// sigNoteSleep waits for a note created by sigNoteSetup to be woken.
129func sigNoteSleep(*note) {
130	for {
131		var b byte
132		entersyscallblock()
133		n := read(sigNoteRead, unsafe.Pointer(&b), 1)
134		exitsyscall()
135		if n != -_EINTR {
136			return
137		}
138	}
139}
140
141// BSD interface for threading.
142func osinit() {
143	// pthread_create delayed until end of goenvs so that we
144	// can look at the environment first.
145
146	ncpu = getncpu()
147	physPageSize = getPageSize()
148
149	osinit_hack()
150}
151
152func sysctlbynameInt32(name []byte) (int32, int32) {
153	out := int32(0)
154	nout := unsafe.Sizeof(out)
155	ret := sysctlbyname(&name[0], (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
156	return ret, out
157}
158
159//go:linkname internal_cpu_getsysctlbyname internal/cpu.getsysctlbyname
160func internal_cpu_getsysctlbyname(name []byte) (int32, int32) {
161	return sysctlbynameInt32(name)
162}
163
164const (
165	_CTL_HW      = 6
166	_HW_NCPU     = 3
167	_HW_PAGESIZE = 7
168)
169
170func getncpu() int32 {
171	// Use sysctl to fetch hw.ncpu.
172	mib := [2]uint32{_CTL_HW, _HW_NCPU}
173	out := uint32(0)
174	nout := unsafe.Sizeof(out)
175	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
176	if ret >= 0 && int32(out) > 0 {
177		return int32(out)
178	}
179	return 1
180}
181
182func getPageSize() uintptr {
183	// Use sysctl to fetch hw.pagesize.
184	mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
185	out := uint32(0)
186	nout := unsafe.Sizeof(out)
187	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
188	if ret >= 0 && int32(out) > 0 {
189		return uintptr(out)
190	}
191	return 0
192}
193
194var urandom_dev = []byte("/dev/urandom\x00")
195
196//go:nosplit
197func readRandom(r []byte) int {
198	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
199	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
200	closefd(fd)
201	return int(n)
202}
203
204func goenvs() {
205	goenvs_unix()
206}
207
208// May run with m.p==nil, so write barriers are not allowed.
209//
210//go:nowritebarrierrec
211func newosproc(mp *m) {
212	stk := unsafe.Pointer(mp.g0.stack.hi)
213	if false {
214		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n")
215	}
216
217	// Initialize an attribute object.
218	var attr pthreadattr
219	var err int32
220	err = pthread_attr_init(&attr)
221	if err != 0 {
222		writeErrStr(failthreadcreate)
223		exit(1)
224	}
225
226	// Find out OS stack size for our own stack guard.
227	var stacksize uintptr
228	if pthread_attr_getstacksize(&attr, &stacksize) != 0 {
229		writeErrStr(failthreadcreate)
230		exit(1)
231	}
232	mp.g0.stack.hi = stacksize // for mstart
233
234	// Tell the pthread library we won't join with this thread.
235	if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
236		writeErrStr(failthreadcreate)
237		exit(1)
238	}
239
240	// Finally, create the thread. It starts at mstart_stub, which does some low-level
241	// setup and then calls mstart.
242	var oset sigset
243	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
244	err = retryOnEAGAIN(func() int32 {
245		return pthread_create(&attr, abi.FuncPCABI0(mstart_stub), unsafe.Pointer(mp))
246	})
247	sigprocmask(_SIG_SETMASK, &oset, nil)
248	if err != 0 {
249		writeErrStr(failthreadcreate)
250		exit(1)
251	}
252}
253
254// glue code to call mstart from pthread_create.
255func mstart_stub()
256
257// newosproc0 is a version of newosproc that can be called before the runtime
258// is initialized.
259//
260// This function is not safe to use after initialization as it does not pass an M as fnarg.
261//
262//go:nosplit
263func newosproc0(stacksize uintptr, fn uintptr) {
264	// Initialize an attribute object.
265	var attr pthreadattr
266	var err int32
267	err = pthread_attr_init(&attr)
268	if err != 0 {
269		writeErrStr(failthreadcreate)
270		exit(1)
271	}
272
273	// The caller passes in a suggested stack size,
274	// from when we allocated the stack and thread ourselves,
275	// without libpthread. Now that we're using libpthread,
276	// we use the OS default stack size instead of the suggestion.
277	// Find out that stack size for our own stack guard.
278	if pthread_attr_getstacksize(&attr, &stacksize) != 0 {
279		writeErrStr(failthreadcreate)
280		exit(1)
281	}
282	g0.stack.hi = stacksize // for mstart
283	memstats.stacks_sys.add(int64(stacksize))
284
285	// Tell the pthread library we won't join with this thread.
286	if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
287		writeErrStr(failthreadcreate)
288		exit(1)
289	}
290
291	// Finally, create the thread. It starts at mstart_stub, which does some low-level
292	// setup and then calls mstart.
293	var oset sigset
294	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
295	err = pthread_create(&attr, fn, nil)
296	sigprocmask(_SIG_SETMASK, &oset, nil)
297	if err != 0 {
298		writeErrStr(failthreadcreate)
299		exit(1)
300	}
301}
302
303// Called to do synchronous initialization of Go code built with
304// -buildmode=c-archive or -buildmode=c-shared.
305// None of the Go runtime is initialized.
306//
307//go:nosplit
308//go:nowritebarrierrec
309func libpreinit() {
310	initsig(true)
311}
312
313// Called to initialize a new m (including the bootstrap m).
314// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
315func mpreinit(mp *m) {
316	mp.gsignal = malg(32 * 1024) // OS X wants >= 8K
317	mp.gsignal.m = mp
318	if GOOS == "darwin" && GOARCH == "arm64" {
319		// mlock the signal stack to work around a kernel bug where it may
320		// SIGILL when the signal stack is not faulted in while a signal
321		// arrives. See issue 42774.
322		mlock(unsafe.Pointer(mp.gsignal.stack.hi-physPageSize), physPageSize)
323	}
324}
325
326// Called to initialize a new m (including the bootstrap m).
327// Called on the new thread, cannot allocate memory.
328func minit() {
329	// iOS does not support alternate signal stack.
330	// The signal handler handles it directly.
331	if !(GOOS == "ios" && GOARCH == "arm64") {
332		minitSignalStack()
333	}
334	minitSignalMask()
335	getg().m.procid = uint64(pthread_self())
336}
337
338// Called from dropm to undo the effect of an minit.
339//
340//go:nosplit
341func unminit() {
342	// iOS does not support alternate signal stack.
343	// See minit.
344	if !(GOOS == "ios" && GOARCH == "arm64") {
345		unminitSignals()
346	}
347	getg().m.procid = 0
348}
349
350// Called from exitm, but not from drop, to undo the effect of thread-owned
351// resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
352func mdestroy(mp *m) {
353}
354
355//go:nosplit
356func osyield_no_g() {
357	usleep_no_g(1)
358}
359
360//go:nosplit
361func osyield() {
362	usleep(1)
363}
364
365const (
366	_NSIG        = 32
367	_SI_USER     = 0 /* empirically true, but not what headers say */
368	_SIG_BLOCK   = 1
369	_SIG_UNBLOCK = 2
370	_SIG_SETMASK = 3
371	_SS_DISABLE  = 4
372)
373
374//extern SigTabTT runtime·sigtab[];
375
376type sigset uint32
377
378var sigset_all = ^sigset(0)
379
380//go:nosplit
381//go:nowritebarrierrec
382func setsig(i uint32, fn uintptr) {
383	var sa usigactiont
384	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
385	sa.sa_mask = ^uint32(0)
386	if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go
387		if iscgo {
388			fn = abi.FuncPCABI0(cgoSigtramp)
389		} else {
390			fn = abi.FuncPCABI0(sigtramp)
391		}
392	}
393	*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
394	sigaction(i, &sa, nil)
395}
396
397// sigtramp is the callback from libc when a signal is received.
398// It is called with the C calling convention.
399func sigtramp()
400func cgoSigtramp()
401
402//go:nosplit
403//go:nowritebarrierrec
404func setsigstack(i uint32) {
405	var osa usigactiont
406	sigaction(i, nil, &osa)
407	handler := *(*uintptr)(unsafe.Pointer(&osa.__sigaction_u))
408	if osa.sa_flags&_SA_ONSTACK != 0 {
409		return
410	}
411	var sa usigactiont
412	*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = handler
413	sa.sa_mask = osa.sa_mask
414	sa.sa_flags = osa.sa_flags | _SA_ONSTACK
415	sigaction(i, &sa, nil)
416}
417
418//go:nosplit
419//go:nowritebarrierrec
420func getsig(i uint32) uintptr {
421	var sa usigactiont
422	sigaction(i, nil, &sa)
423	return *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u))
424}
425
426// setSignalstackSP sets the ss_sp field of a stackt.
427//
428//go:nosplit
429func setSignalstackSP(s *stackt, sp uintptr) {
430	*(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp
431}
432
433//go:nosplit
434//go:nowritebarrierrec
435func sigaddset(mask *sigset, i int) {
436	*mask |= 1 << (uint32(i) - 1)
437}
438
439func sigdelset(mask *sigset, i int) {
440	*mask &^= 1 << (uint32(i) - 1)
441}
442
443func setProcessCPUProfiler(hz int32) {
444	setProcessCPUProfilerTimer(hz)
445}
446
447func setThreadCPUProfiler(hz int32) {
448	setThreadCPUProfilerHz(hz)
449}
450
451//go:nosplit
452func validSIGPROF(mp *m, c *sigctxt) bool {
453	return true
454}
455
456//go:linkname executablePath os.executablePath
457var executablePath string
458
459func sysargs(argc int32, argv **byte) {
460	// skip over argv, envv and the first string will be the path
461	n := argc + 1
462	for argv_index(argv, n) != nil {
463		n++
464	}
465	executablePath = gostringnocopy(argv_index(argv, n+1))
466
467	// strip "executable_path=" prefix if available, it's added after OS X 10.11.
468	const prefix = "executable_path="
469	if len(executablePath) > len(prefix) && executablePath[:len(prefix)] == prefix {
470		executablePath = executablePath[len(prefix):]
471	}
472}
473
474func signalM(mp *m, sig int) {
475	pthread_kill(pthread(mp.procid), uint32(sig))
476}
477
478// sigPerThreadSyscall is only used on linux, so we assign a bogus signal
479// number.
480const sigPerThreadSyscall = 1 << 31
481
482//go:nosplit
483func runPerThreadSyscall() {
484	throw("runPerThreadSyscall only valid on linux")
485}
486