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
5package runtime
6
7import (
8	"internal/abi"
9	"internal/runtime/atomic"
10	"unsafe"
11)
12
13type mOS struct {
14	waitsemacount uint32
15}
16
17const (
18	_ESRCH       = 3
19	_EWOULDBLOCK = _EAGAIN
20	_ENOTSUP     = 91
21
22	// From OpenBSD's sys/time.h
23	_CLOCK_REALTIME  = 0
24	_CLOCK_VIRTUAL   = 1
25	_CLOCK_PROF      = 2
26	_CLOCK_MONOTONIC = 3
27)
28
29type sigset uint32
30
31var sigset_all = ^sigset(0)
32
33// From OpenBSD's <sys/sysctl.h>
34const (
35	_CTL_HW        = 6
36	_HW_NCPU       = 3
37	_HW_PAGESIZE   = 7
38	_HW_NCPUONLINE = 25
39)
40
41func sysctlInt(mib []uint32) (int32, bool) {
42	var out int32
43	nout := unsafe.Sizeof(out)
44	ret := sysctl(&mib[0], uint32(len(mib)), (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
45	if ret < 0 {
46		return 0, false
47	}
48	return out, true
49}
50
51func sysctlUint64(mib []uint32) (uint64, bool) {
52	var out uint64
53	nout := unsafe.Sizeof(out)
54	ret := sysctl(&mib[0], uint32(len(mib)), (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
55	if ret < 0 {
56		return 0, false
57	}
58	return out, true
59}
60
61//go:linkname internal_cpu_sysctlUint64 internal/cpu.sysctlUint64
62func internal_cpu_sysctlUint64(mib []uint32) (uint64, bool) {
63	return sysctlUint64(mib)
64}
65
66func getncpu() int32 {
67	// Try hw.ncpuonline first because hw.ncpu would report a number twice as
68	// high as the actual CPUs running on OpenBSD 6.4 with hyperthreading
69	// disabled (hw.smt=0). See https://golang.org/issue/30127
70	if n, ok := sysctlInt([]uint32{_CTL_HW, _HW_NCPUONLINE}); ok {
71		return int32(n)
72	}
73	if n, ok := sysctlInt([]uint32{_CTL_HW, _HW_NCPU}); ok {
74		return int32(n)
75	}
76	return 1
77}
78
79func getPageSize() uintptr {
80	if ps, ok := sysctlInt([]uint32{_CTL_HW, _HW_PAGESIZE}); ok {
81		return uintptr(ps)
82	}
83	return 0
84}
85
86//go:nosplit
87func semacreate(mp *m) {
88}
89
90//go:nosplit
91func semasleep(ns int64) int32 {
92	gp := getg()
93
94	// Compute sleep deadline.
95	var tsp *timespec
96	if ns >= 0 {
97		var ts timespec
98		ts.setNsec(ns + nanotime())
99		tsp = &ts
100	}
101
102	for {
103		v := atomic.Load(&gp.m.waitsemacount)
104		if v > 0 {
105			if atomic.Cas(&gp.m.waitsemacount, v, v-1) {
106				return 0 // semaphore acquired
107			}
108			continue
109		}
110
111		// Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0.
112		//
113		// From OpenBSD's __thrsleep(2) manual:
114		// "The abort argument, if not NULL, points to an int that will
115		// be examined [...] immediately before blocking. If that int
116		// is non-zero then __thrsleep() will immediately return EINTR
117		// without blocking."
118		ret := thrsleep(uintptr(unsafe.Pointer(&gp.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &gp.m.waitsemacount)
119		if ret == _EWOULDBLOCK {
120			return -1
121		}
122	}
123}
124
125//go:nosplit
126func semawakeup(mp *m) {
127	atomic.Xadd(&mp.waitsemacount, 1)
128	ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
129	if ret != 0 && ret != _ESRCH {
130		// semawakeup can be called on signal stack.
131		systemstack(func() {
132			print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
133		})
134	}
135}
136
137func osinit() {
138	ncpu = getncpu()
139	physPageSize = getPageSize()
140}
141
142var urandom_dev = []byte("/dev/urandom\x00")
143
144//go:nosplit
145func readRandom(r []byte) int {
146	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
147	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
148	closefd(fd)
149	return int(n)
150}
151
152func goenvs() {
153	goenvs_unix()
154}
155
156// Called to initialize a new m (including the bootstrap m).
157// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
158func mpreinit(mp *m) {
159	gsignalSize := int32(32 * 1024)
160	if GOARCH == "mips64" {
161		gsignalSize = int32(64 * 1024)
162	}
163	mp.gsignal = malg(gsignalSize)
164	mp.gsignal.m = mp
165}
166
167// Called to initialize a new m (including the bootstrap m).
168// Called on the new thread, can not allocate memory.
169func minit() {
170	getg().m.procid = uint64(getthrid())
171	minitSignals()
172}
173
174// Called from dropm to undo the effect of an minit.
175//
176//go:nosplit
177func unminit() {
178	unminitSignals()
179	getg().m.procid = 0
180}
181
182// Called from exitm, but not from drop, to undo the effect of thread-owned
183// resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
184func mdestroy(mp *m) {
185}
186
187func sigtramp()
188
189type sigactiont struct {
190	sa_sigaction uintptr
191	sa_mask      uint32
192	sa_flags     int32
193}
194
195//go:nosplit
196//go:nowritebarrierrec
197func setsig(i uint32, fn uintptr) {
198	var sa sigactiont
199	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
200	sa.sa_mask = uint32(sigset_all)
201	if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go
202		fn = abi.FuncPCABI0(sigtramp)
203	}
204	sa.sa_sigaction = fn
205	sigaction(i, &sa, nil)
206}
207
208//go:nosplit
209//go:nowritebarrierrec
210func setsigstack(i uint32) {
211	throw("setsigstack")
212}
213
214//go:nosplit
215//go:nowritebarrierrec
216func getsig(i uint32) uintptr {
217	var sa sigactiont
218	sigaction(i, nil, &sa)
219	return sa.sa_sigaction
220}
221
222// setSignalstackSP sets the ss_sp field of a stackt.
223//
224//go:nosplit
225func setSignalstackSP(s *stackt, sp uintptr) {
226	s.ss_sp = sp
227}
228
229//go:nosplit
230//go:nowritebarrierrec
231func sigaddset(mask *sigset, i int) {
232	*mask |= 1 << (uint32(i) - 1)
233}
234
235func sigdelset(mask *sigset, i int) {
236	*mask &^= 1 << (uint32(i) - 1)
237}
238
239//go:nosplit
240func (c *sigctxt) fixsigcode(sig uint32) {
241}
242
243func setProcessCPUProfiler(hz int32) {
244	setProcessCPUProfilerTimer(hz)
245}
246
247func setThreadCPUProfiler(hz int32) {
248	setThreadCPUProfilerHz(hz)
249}
250
251//go:nosplit
252func validSIGPROF(mp *m, c *sigctxt) bool {
253	return true
254}
255
256func osStackAlloc(s *mspan) {
257	osStackRemap(s, _MAP_STACK)
258}
259
260func osStackFree(s *mspan) {
261	// Undo MAP_STACK.
262	osStackRemap(s, 0)
263}
264
265func osStackRemap(s *mspan, flags int32) {
266	a, err := mmap(unsafe.Pointer(s.base()), s.npages*pageSize, _PROT_READ|_PROT_WRITE, _MAP_PRIVATE|_MAP_ANON|_MAP_FIXED|flags, -1, 0)
267	if err != 0 || uintptr(a) != s.base() {
268		print("runtime: remapping stack memory ", hex(s.base()), " ", s.npages*pageSize, " a=", a, " err=", err, "\n")
269		throw("remapping stack memory failed")
270	}
271}
272
273//go:nosplit
274func raise(sig uint32) {
275	thrkill(getthrid(), int(sig))
276}
277
278func signalM(mp *m, sig int) {
279	thrkill(int32(mp.procid), sig)
280}
281
282// sigPerThreadSyscall is only used on linux, so we assign a bogus signal
283// number.
284const sigPerThreadSyscall = 1 << 31
285
286//go:nosplit
287func runPerThreadSyscall() {
288	throw("runPerThreadSyscall only valid on linux")
289}
290