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