blob: a4c987470017bf37977e2cbaa46270eb9a0dc7ca [file] [log] [blame]
Russ Coxe785e3a2014-11-11 17:08:54 -05001// 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 "unsafe"
8
9//extern SigTabTT runtimeĀ·sigtab[];
10
11var sigset_none = uint32(0)
12var sigset_all = ^uint32(0)
13
14func unimplemented(name string) {
15 println(name, "not implemented")
16 *(*int)(unsafe.Pointer(uintptr(1231))) = 1231
17}
18
19//go:nosplit
20func semawakeup(mp *m) {
21 mach_semrelease(uint32(mp.waitsema))
22}
23
24//go:nosplit
25func semacreate() uintptr {
26 var x uintptr
Russ Cox656be312014-11-12 14:54:31 -050027 systemstack(func() {
Russ Coxe785e3a2014-11-11 17:08:54 -050028 x = uintptr(mach_semcreate())
29 })
30 return x
31}
32
33// BSD interface for threading.
34func osinit() {
35 // bsdthread_register delayed until end of goenvs so that we
36 // can look at the environment first.
37
38 // Use sysctl to fetch hw.ncpu.
39 mib := [2]uint32{6, 3}
40 out := uint32(0)
41 nout := unsafe.Sizeof(out)
42 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
43 if ret >= 0 {
44 ncpu = int32(out)
45 }
46}
47
Keith Randall1de9c402015-01-08 15:30:22 -080048var urandom_dev = []byte("/dev/urandom\x00")
Russ Coxe785e3a2014-11-11 17:08:54 -050049
50//go:nosplit
Keith Randall6820be22014-12-09 14:40:40 -080051func getRandomData(r []byte) {
Russ Coxe785e3a2014-11-11 17:08:54 -050052 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
Keith Randall6820be22014-12-09 14:40:40 -080053 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
David Crawshawcea272d2015-04-13 19:37:04 -040054 closefd(fd)
Keith Randall6820be22014-12-09 14:40:40 -080055 extendRandom(r, int(n))
Russ Coxe785e3a2014-11-11 17:08:54 -050056}
57
58func goenvs() {
59 goenvs_unix()
60
61 // Register our thread-creation callback (see sys_darwin_{amd64,386}.s)
62 // but only if we're not using cgo. If we are using cgo we need
63 // to let the C pthread library install its own thread-creation callback.
64 if !iscgo {
65 if bsdthread_register() != 0 {
66 if gogetenv("DYLD_INSERT_LIBRARIES") != "" {
Keith Randallb2a950b2014-12-27 20:58:00 -080067 throw("runtime: bsdthread_register error (unset DYLD_INSERT_LIBRARIES)")
Russ Coxe785e3a2014-11-11 17:08:54 -050068 }
Keith Randallb2a950b2014-12-27 20:58:00 -080069 throw("runtime: bsdthread_register error")
Russ Coxe785e3a2014-11-11 17:08:54 -050070 }
71 }
72}
73
Austin Clements9e6f7aa2015-03-29 10:20:54 -040074// May run with m.p==nil, so write barriers are not allowed.
Austin Clements392336f2015-03-26 15:50:22 -040075//go:nowritebarrier
Russ Coxe785e3a2014-11-11 17:08:54 -050076func newosproc(mp *m, stk unsafe.Pointer) {
77 mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
78 if false {
79 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int(mp.tls[0]), " ostk=", &mp, "\n")
80 }
81
82 var oset uint32
83 sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
David Crawshawb0a85f52015-04-08 14:16:26 -040084 errno := bsdthread_create(stk, unsafe.Pointer(mp), funcPC(mstart))
Russ Coxe785e3a2014-11-11 17:08:54 -050085 sigprocmask(_SIG_SETMASK, &oset, nil)
86
87 if errno < 0 {
88 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", -errno, ")\n")
Keith Randallb2a950b2014-12-27 20:58:00 -080089 throw("runtime.newosproc")
Russ Coxe785e3a2014-11-11 17:08:54 -050090 }
91}
92
David Crawshawb0a85f52015-04-08 14:16:26 -040093// newosproc0 is a version of newosproc that can be called before the runtime
94// is initialized.
95//
96// As Go uses bsdthread_register when running without cgo, this function is
97// not safe to use after initialization as it does not pass an M as fnarg.
98//
99//go:nosplit
100func newosproc0(stacksize uintptr, fn unsafe.Pointer, fnarg uintptr) {
101 var dummy uint64
102 stack := sysAlloc(stacksize, &dummy)
103 if stack == nil {
104 write(2, unsafe.Pointer(&failallocatestack[0]), int32(len(failallocatestack)))
105 exit(1)
106 }
107 stk := unsafe.Pointer(uintptr(stack) + stacksize)
108
109 var oset uint32
110 sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
111 errno := bsdthread_create(stk, fn, fnarg)
112 sigprocmask(_SIG_SETMASK, &oset, nil)
113
114 if errno < 0 {
115 write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
116 exit(1)
117 }
118}
119
120var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n")
121var failthreadcreate = []byte("runtime: failed to create new OS thread\n")
122
Russ Coxe785e3a2014-11-11 17:08:54 -0500123// Called to initialize a new m (including the bootstrap m).
124// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
125func mpreinit(mp *m) {
126 mp.gsignal = malg(32 * 1024) // OS X wants >= 8K
127 mp.gsignal.m = mp
128}
129
130// Called to initialize a new m (including the bootstrap m).
131// Called on the new thread, can not allocate memory.
132func minit() {
133 // Initialize signal handling.
134 _g_ := getg()
135 signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
136 sigprocmask(_SIG_SETMASK, &sigset_none, nil)
137}
138
139// Called from dropm to undo the effect of an minit.
140func unminit() {
141 signalstack(nil, 0)
142}
143
144// Mach IPC, to get at semaphores
145// Definitions are in /usr/include/mach on a Mac.
146
147func macherror(r int32, fn string) {
148 print("mach error ", fn, ": ", r, "\n")
Keith Randallb2a950b2014-12-27 20:58:00 -0800149 throw("mach error")
Russ Coxe785e3a2014-11-11 17:08:54 -0500150}
151
152const _DebugMach = false
153
154var zerondr machndr
155
156func mach_msgh_bits(a, b uint32) uint32 {
157 return a | b<<8
158}
159
160func mach_msg(h *machheader, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32 {
161 // TODO: Loop on interrupt.
162 return mach_msg_trap(unsafe.Pointer(h), op, send_size, rcv_size, rcv_name, timeout, notify)
163}
164
165// Mach RPC (MIG)
166const (
167 _MinMachMsg = 48
168 _MachReply = 100
169)
170
171type codemsg struct {
172 h machheader
173 ndr machndr
174 code int32
175}
176
177func machcall(h *machheader, maxsize int32, rxsize int32) int32 {
178 _g_ := getg()
179 port := _g_.m.machport
180 if port == 0 {
181 port = mach_reply_port()
182 _g_.m.machport = port
183 }
184
185 h.msgh_bits |= mach_msgh_bits(_MACH_MSG_TYPE_COPY_SEND, _MACH_MSG_TYPE_MAKE_SEND_ONCE)
186 h.msgh_local_port = port
187 h.msgh_reserved = 0
188 id := h.msgh_id
189
190 if _DebugMach {
191 p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h))
192 print("send:\t")
193 var i uint32
194 for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ {
195 print(" ", p[i])
196 if i%8 == 7 {
197 print("\n\t")
198 }
199 }
200 if i%8 != 0 {
201 print("\n")
202 }
203 }
204 ret := mach_msg(h, _MACH_SEND_MSG|_MACH_RCV_MSG, h.msgh_size, uint32(maxsize), port, 0, 0)
205 if ret != 0 {
206 if _DebugMach {
207 print("mach_msg error ", ret, "\n")
208 }
209 return ret
210 }
211 if _DebugMach {
212 p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h))
213 var i uint32
214 for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ {
215 print(" ", p[i])
216 if i%8 == 7 {
217 print("\n\t")
218 }
219 }
220 if i%8 != 0 {
221 print("\n")
222 }
223 }
224 if h.msgh_id != id+_MachReply {
225 if _DebugMach {
226 print("mach_msg _MachReply id mismatch ", h.msgh_id, " != ", id+_MachReply, "\n")
227 }
228 return -303 // MIG_REPLY_MISMATCH
229 }
230 // Look for a response giving the return value.
231 // Any call can send this back with an error,
232 // and some calls only have return values so they
233 // send it back on success too. I don't quite see how
234 // you know it's one of these and not the full response
235 // format, so just look if the message is right.
236 c := (*codemsg)(unsafe.Pointer(h))
237 if uintptr(h.msgh_size) == unsafe.Sizeof(*c) && h.msgh_bits&_MACH_MSGH_BITS_COMPLEX == 0 {
238 if _DebugMach {
239 print("mig result ", c.code, "\n")
240 }
241 return c.code
242 }
243 if h.msgh_size != uint32(rxsize) {
244 if _DebugMach {
245 print("mach_msg _MachReply size mismatch ", h.msgh_size, " != ", rxsize, "\n")
246 }
247 return -307 // MIG_ARRAY_TOO_LARGE
248 }
249 return 0
250}
251
252// Semaphores!
253
254const (
255 tmach_semcreate = 3418
256 rmach_semcreate = tmach_semcreate + _MachReply
257
258 tmach_semdestroy = 3419
259 rmach_semdestroy = tmach_semdestroy + _MachReply
260
261 _KERN_ABORTED = 14
262 _KERN_OPERATION_TIMED_OUT = 49
263)
264
265type tmach_semcreatemsg struct {
266 h machheader
267 ndr machndr
268 policy int32
269 value int32
270}
271
272type rmach_semcreatemsg struct {
273 h machheader
274 body machbody
275 semaphore machport
276}
277
278type tmach_semdestroymsg struct {
279 h machheader
280 body machbody
281 semaphore machport
282}
283
284func mach_semcreate() uint32 {
285 var m [256]uint8
286 tx := (*tmach_semcreatemsg)(unsafe.Pointer(&m))
287 rx := (*rmach_semcreatemsg)(unsafe.Pointer(&m))
288
289 tx.h.msgh_bits = 0
290 tx.h.msgh_size = uint32(unsafe.Sizeof(*tx))
291 tx.h.msgh_remote_port = mach_task_self()
292 tx.h.msgh_id = tmach_semcreate
293 tx.ndr = zerondr
294
295 tx.policy = 0 // 0 = SYNC_POLICY_FIFO
296 tx.value = 0
297
298 for {
299 r := machcall(&tx.h, int32(unsafe.Sizeof(m)), int32(unsafe.Sizeof(*rx)))
300 if r == 0 {
301 break
302 }
303 if r == _KERN_ABORTED { // interrupted
304 continue
305 }
306 macherror(r, "semaphore_create")
307 }
308 if rx.body.msgh_descriptor_count != 1 {
309 unimplemented("mach_semcreate desc count")
310 }
311 return rx.semaphore.name
312}
313
314func mach_semdestroy(sem uint32) {
315 var m [256]uint8
316 tx := (*tmach_semdestroymsg)(unsafe.Pointer(&m))
317
318 tx.h.msgh_bits = _MACH_MSGH_BITS_COMPLEX
319 tx.h.msgh_size = uint32(unsafe.Sizeof(*tx))
320 tx.h.msgh_remote_port = mach_task_self()
321 tx.h.msgh_id = tmach_semdestroy
322 tx.body.msgh_descriptor_count = 1
323 tx.semaphore.name = sem
324 tx.semaphore.disposition = _MACH_MSG_TYPE_MOVE_SEND
325 tx.semaphore._type = 0
326
327 for {
328 r := machcall(&tx.h, int32(unsafe.Sizeof(m)), 0)
329 if r == 0 {
330 break
331 }
332 if r == _KERN_ABORTED { // interrupted
333 continue
334 }
335 macherror(r, "semaphore_destroy")
336 }
337}
338
339// The other calls have simple system call traps in sys_darwin_{amd64,386}.s
340
341func mach_semaphore_wait(sema uint32) int32
342func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
343func mach_semaphore_signal(sema uint32) int32
344func mach_semaphore_signal_all(sema uint32) int32
345
346func semasleep1(ns int64) int32 {
347 _g_ := getg()
348
349 if ns >= 0 {
350 var nsecs int32
351 secs := timediv(ns, 1000000000, &nsecs)
352 r := mach_semaphore_timedwait(uint32(_g_.m.waitsema), uint32(secs), uint32(nsecs))
353 if r == _KERN_ABORTED || r == _KERN_OPERATION_TIMED_OUT {
354 return -1
355 }
356 if r != 0 {
357 macherror(r, "semaphore_wait")
358 }
359 return 0
360 }
361
362 for {
363 r := mach_semaphore_wait(uint32(_g_.m.waitsema))
364 if r == 0 {
365 break
366 }
367 if r == _KERN_ABORTED { // interrupted
368 continue
369 }
370 macherror(r, "semaphore_wait")
371 }
372 return 0
373}
374
375//go:nosplit
376func semasleep(ns int64) int32 {
377 var r int32
Russ Cox656be312014-11-12 14:54:31 -0500378 systemstack(func() {
Russ Coxe785e3a2014-11-11 17:08:54 -0500379 r = semasleep1(ns)
380 })
381 return r
382}
383
384//go:nosplit
385func mach_semrelease(sem uint32) {
386 for {
387 r := mach_semaphore_signal(sem)
388 if r == 0 {
389 break
390 }
391 if r == _KERN_ABORTED { // interrupted
392 continue
393 }
394
395 // mach_semrelease must be completely nosplit,
396 // because it is called from Go code.
Russ Cox656be312014-11-12 14:54:31 -0500397 // If we're going to die, start that process on the system stack
Russ Coxe785e3a2014-11-11 17:08:54 -0500398 // to avoid a Go stack split.
Russ Cox656be312014-11-12 14:54:31 -0500399 systemstack(func() { macherror(r, "semaphore_signal") })
Russ Coxe785e3a2014-11-11 17:08:54 -0500400 }
401}
402
403//go:nosplit
404func osyield() {
405 usleep(1)
406}
407
408func memlimit() uintptr {
409 // NOTE(rsc): Could use getrlimit here,
410 // like on FreeBSD or Linux, but Darwin doesn't enforce
411 // ulimit -v, so it's unclear why we'd try to stay within
412 // the limit.
413 return 0
414}
415
416func setsig(i int32, fn uintptr, restart bool) {
417 var sa sigactiont
418 memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
419 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
420 if restart {
421 sa.sa_flags |= _SA_RESTART
422 }
423 sa.sa_mask = ^uint32(0)
424 sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp)) // runtimeĀ·sigtramp's job is to call into real handler
425 *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
426 sigaction(uint32(i), &sa, nil)
427}
428
Austin Clements675eb722014-12-19 16:16:17 -0500429func setsigstack(i int32) {
Keith Randallb2a950b2014-12-27 20:58:00 -0800430 throw("setsigstack")
Austin Clements675eb722014-12-19 16:16:17 -0500431}
432
Russ Coxe785e3a2014-11-11 17:08:54 -0500433func getsig(i int32) uintptr {
434 var sa sigactiont
435 memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
436 sigaction(uint32(i), nil, &sa)
437 return *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u))
438}
439
440func signalstack(p *byte, n int32) {
441 var st stackt
442 st.ss_sp = p
443 st.ss_size = uintptr(n)
444 st.ss_flags = 0
445 if p == nil {
446 st.ss_flags = _SS_DISABLE
447 }
448 sigaltstack(&st, nil)
449}
450
451func unblocksignals() {
452 sigprocmask(_SIG_SETMASK, &sigset_none, nil)
453}