]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/os1_openbsd.go
[dev.cc] runtime: fix lfstack for amd64 addresses in top half of addr space
[gostls13.git] / src / runtime / os1_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 "unsafe"
8
9 const (
10         ESRCH       = 3
11         EAGAIN      = 35
12         EWOULDBLOCK = EAGAIN
13         ENOTSUP     = 91
14
15         // From OpenBSD's sys/time.h
16         CLOCK_REALTIME  = 0
17         CLOCK_VIRTUAL   = 1
18         CLOCK_PROF      = 2
19         CLOCK_MONOTONIC = 3
20 )
21
22 var sigset_none = uint32(0)
23 var sigset_all = ^sigset_none
24
25 // From OpenBSD's <sys/sysctl.h>
26 const (
27         CTL_HW  = 6
28         HW_NCPU = 3
29 )
30
31 func getncpu() int32 {
32         mib := [2]uint32{CTL_HW, HW_NCPU}
33         out := uint32(0)
34         nout := unsafe.Sizeof(out)
35
36         // Fetch hw.ncpu via sysctl.
37         ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
38         if ret >= 0 {
39                 return int32(out)
40         }
41         return 1
42 }
43
44 //go:nosplit
45 func semacreate() uintptr {
46         return 1
47 }
48
49 //go:nosplit
50 func semasleep(ns int64) int32 {
51         _g_ := getg()
52
53         // Compute sleep deadline.
54         var tsp *timespec
55         if ns >= 0 {
56                 var ts timespec
57                 var nsec int32
58                 ns += nanotime()
59                 ts.set_sec(timediv(ns, 1000000000, &nsec))
60                 ts.set_nsec(nsec)
61                 tsp = &ts
62         }
63
64         for {
65                 // spin-mutex lock
66                 for {
67                         if xchg(&_g_.m.waitsemalock, 1) == 0 {
68                                 break
69                         }
70                         osyield()
71                 }
72
73                 if _g_.m.waitsemacount != 0 {
74                         // semaphore is available.
75                         _g_.m.waitsemacount--
76                         // spin-mutex unlock
77                         atomicstore(&_g_.m.waitsemalock, 0)
78                         return 0 // semaphore acquired
79                 }
80
81                 // sleep until semaphore != 0 or timeout.
82                 // thrsleep unlocks m.waitsemalock.
83                 ret := thrsleep((uintptr)(unsafe.Pointer(&_g_.m.waitsemacount)), CLOCK_MONOTONIC, tsp, (uintptr)(unsafe.Pointer(&_g_.m.waitsemalock)), (*int32)(unsafe.Pointer(&_g_.m.waitsemacount)))
84                 if ret == EWOULDBLOCK {
85                         return -1
86                 }
87         }
88 }
89
90 //go:nosplit
91 func semawakeup(mp *m) {
92         // spin-mutex lock
93         for {
94                 if xchg(&mp.waitsemalock, 1) == 0 {
95                         break
96                 }
97                 osyield()
98         }
99         mp.waitsemacount++
100         ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
101         if ret != 0 && ret != ESRCH {
102                 // semawakeup can be called on signal stack.
103                 systemstack(func() {
104                         print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
105                 })
106         }
107         // spin-mutex unlock
108         atomicstore(&mp.waitsemalock, 0)
109 }
110
111 func newosproc(mp *m, stk unsafe.Pointer) {
112         if false {
113                 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int32(mp.tls[0]), " ostk=", &mp, "\n")
114         }
115
116         mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
117
118         param := tforkt{
119                 tf_tcb:   unsafe.Pointer(&mp.tls[0]),
120                 tf_tid:   (*int32)(unsafe.Pointer(&mp.procid)),
121                 tf_stack: uintptr(stk),
122         }
123
124         oset := sigprocmask(_SIG_SETMASK, sigset_all)
125         ret := tfork(&param, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart))
126         sigprocmask(_SIG_SETMASK, oset)
127
128         if ret < 0 {
129                 print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
130                 if ret == -ENOTSUP {
131                         print("runtime: is kern.rthreads disabled?\n")
132                 }
133                 gothrow("runtime.newosproc")
134         }
135 }
136
137 func osinit() {
138         ncpu = getncpu()
139 }
140
141 var urandom_data [_HashRandomBytes]byte
142 var urandom_dev = []byte("/dev/urandom\x00")
143
144 //go:nosplit
145 func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) {
146         fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
147         if read(fd, unsafe.Pointer(&urandom_data), _HashRandomBytes) == _HashRandomBytes {
148                 *rnd = unsafe.Pointer(&urandom_data[0])
149                 *rnd_len = _HashRandomBytes
150         } else {
151                 *rnd = nil
152                 *rnd_len = 0
153         }
154         close(fd)
155 }
156
157 func goenvs() {
158         goenvs_unix()
159 }
160
161 // Called to initialize a new m (including the bootstrap m).
162 // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
163 func mpreinit(mp *m) {
164         mp.gsignal = malg(32 * 1024)
165         mp.gsignal.m = mp
166 }
167
168 // Called to initialize a new m (including the bootstrap m).
169 // Called on the new thread, can not allocate memory.
170 func minit() {
171         _g_ := getg()
172
173         // m.procid is a uint64, but tfork writes an int32. Fix it up.
174         _g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
175
176         // Initialize signal handling
177         signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
178         sigprocmask(_SIG_SETMASK, sigset_none)
179 }
180
181 // Called from dropm to undo the effect of an minit.
182 func unminit() {
183         signalstack(nil, 0)
184 }
185
186 func memlimit() uintptr {
187         return 0
188 }
189
190 func sigtramp()
191
192 type sigactiont struct {
193         sa_sigaction uintptr
194         sa_mask      uint32
195         sa_flags     int32
196 }
197
198 func setsig(i int32, fn uintptr, restart bool) {
199         var sa sigactiont
200         sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
201         if restart {
202                 sa.sa_flags |= _SA_RESTART
203         }
204         sa.sa_mask = sigset_all
205         if fn == funcPC(sighandler) {
206                 fn = funcPC(sigtramp)
207         }
208         sa.sa_sigaction = fn
209         sigaction(i, &sa, nil)
210 }
211
212 func getsig(i int32) uintptr {
213         var sa sigactiont
214         sigaction(i, nil, &sa)
215         if sa.sa_sigaction == funcPC(sigtramp) {
216                 return funcPC(sighandler)
217         }
218         return sa.sa_sigaction
219 }
220
221 func signalstack(p *byte, n int32) {
222         var st stackt
223
224         st.ss_sp = uintptr(unsafe.Pointer(p))
225         st.ss_size = uintptr(n)
226         st.ss_flags = 0
227         if p == nil {
228                 st.ss_flags = _SS_DISABLE
229         }
230         sigaltstack(&st, nil)
231 }
232
233 func unblocksignals() {
234         sigprocmask(_SIG_SETMASK, sigset_none)
235 }