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.
10 machport
uint32 // return address for mach ipc
11 waitsema
uint32 // semaphore for parking on locks
15 //extern mach_msg_trap
16 func mach_msg_trap(h unsafe
.Pointer
, op
int32, send_size
, rcv_size
, rcv_name
, timeout
, notify
uint32) int32
18 //extern mach_reply_port
19 func mach_reply_port() uint32
21 //extern mach_task_self
22 func mach_task_self() uint32
24 func unimplemented(name
string) {
25 println(name
, "not implemented")
26 *(*int)(unsafe
.Pointer(uintptr(1231))) = 1231
30 func semawakeup(mp
*m
) {
31 mach_semrelease(mp
.mos
.waitsema
)
35 func semacreate(mp
*m
) {
36 if mp
.mos
.waitsema
!= 0 {
40 mp
.mos
.waitsema
= mach_semcreate()
44 // Mach IPC, to get at semaphores
45 // Definitions are in /usr/include/mach on a Mac.
47 func macherror(r
int32, fn
string) {
48 print("mach error ", fn
, ": ", r
, "\n")
52 const _DebugMach
= false
56 func mach_msgh_bits(a
, b
uint32) uint32 {
60 func mach_msg(h
*machheader
, op
int32, send_size
, rcv_size
, rcv_name
, timeout
, notify
uint32) int32 {
61 // TODO: Loop on interrupt.
62 return mach_msg_trap(unsafe
.Pointer(h
), op
, send_size
, rcv_size
, rcv_name
, timeout
, notify
)
77 func machcall(h
*machheader
, maxsize
int32, rxsize
int32) int32 {
79 port
:= _g_
.m
.mos
.machport
81 port
= mach_reply_port()
82 _g_
.m
.mos
.machport
= port
85 h
.msgh_bits |
= mach_msgh_bits(_MACH_MSG_TYPE_COPY_SEND
, _MACH_MSG_TYPE_MAKE_SEND_ONCE
)
86 h
.msgh_local_port
= port
91 p
:= (*[10000]unsafe
.Pointer
)(unsafe
.Pointer(h
))
94 for i
= 0; i
< h
.msgh_size
/uint32(unsafe
.Sizeof(p
[0])); i
++ {
104 ret
:= mach_msg(h
, _MACH_SEND_MSG|_MACH_RCV_MSG
, h
.msgh_size
, uint32(maxsize
), port
, 0, 0)
107 print("mach_msg error ", ret
, "\n")
112 p
:= (*[10000]unsafe
.Pointer
)(unsafe
.Pointer(h
))
114 for i
= 0; i
< h
.msgh_size
/uint32(unsafe
.Sizeof(p
[0])); i
++ {
124 if h
.msgh_id
!= id
+_MachReply
{
126 print("mach_msg _MachReply id mismatch ", h
.msgh_id
, " != ", id
+_MachReply
, "\n")
128 return -303 // MIG_REPLY_MISMATCH
130 // Look for a response giving the return value.
131 // Any call can send this back with an error,
132 // and some calls only have return values so they
133 // send it back on success too. I don't quite see how
134 // you know it's one of these and not the full response
135 // format, so just look if the message is right.
136 c
:= (*codemsg
)(unsafe
.Pointer(h
))
137 if uintptr(h
.msgh_size
) == unsafe
.Sizeof(*c
) && h
.msgh_bits
&_MACH_MSGH_BITS_COMPLEX
== 0 {
139 print("mig result ", c
.code
, "\n")
143 if h
.msgh_size
!= uint32(rxsize
) {
145 print("mach_msg _MachReply size mismatch ", h
.msgh_size
, " != ", rxsize
, "\n")
147 return -307 // MIG_ARRAY_TOO_LARGE
155 tmach_semcreate
= 3418
156 rmach_semcreate
= tmach_semcreate
+ _MachReply
158 tmach_semdestroy
= 3419
159 rmach_semdestroy
= tmach_semdestroy
+ _MachReply
162 _KERN_OPERATION_TIMED_OUT
= 49
165 type tmach_semcreatemsg
struct {
172 type rmach_semcreatemsg
struct {
178 type tmach_semdestroymsg
struct {
184 func mach_semcreate() uint32 {
186 tx
:= (*tmach_semcreatemsg
)(unsafe
.Pointer(&m
))
187 rx
:= (*rmach_semcreatemsg
)(unsafe
.Pointer(&m
))
190 tx
.h
.msgh_size
= uint32(unsafe
.Sizeof(*tx
))
191 tx
.h
.msgh_remote_port
= mach_task_self()
192 tx
.h
.msgh_id
= tmach_semcreate
195 tx
.policy
= 0 // 0 = SYNC_POLICY_FIFO
199 r
:= machcall(&tx
.h
, int32(unsafe
.Sizeof(m
)), int32(unsafe
.Sizeof(*rx
)))
203 if r
== _KERN_ABORTED
{ // interrupted
206 macherror(r
, "semaphore_create")
208 if rx
.body
.msgh_descriptor_count
!= 1 {
209 unimplemented("mach_semcreate desc count")
211 return rx
.semaphore
.name
214 func mach_semdestroy(sem
uint32) {
216 tx
:= (*tmach_semdestroymsg
)(unsafe
.Pointer(&m
))
218 tx
.h
.msgh_bits
= _MACH_MSGH_BITS_COMPLEX
219 tx
.h
.msgh_size
= uint32(unsafe
.Sizeof(*tx
))
220 tx
.h
.msgh_remote_port
= mach_task_self()
221 tx
.h
.msgh_id
= tmach_semdestroy
222 tx
.body
.msgh_descriptor_count
= 1
223 tx
.semaphore
.name
= sem
224 tx
.semaphore
.disposition
= _MACH_MSG_TYPE_MOVE_SEND
225 tx
.semaphore
._type
= 0
228 r
:= machcall(&tx
.h
, int32(unsafe
.Sizeof(m
)), 0)
232 if r
== _KERN_ABORTED
{ // interrupted
235 macherror(r
, "semaphore_destroy")
239 //extern semaphore_wait
240 func mach_semaphore_wait(sema
uint32) int32
242 //extern semaphore_timedwait
243 func mach_semaphore_timedwait(sema
, sec
, nsec
uint32) int32
245 //extern semaphore_signal
246 func mach_semaphore_signal(sema
uint32) int32
248 //extern semaphore_signal_all
249 func mach_semaphore_signal_all(sema
uint32) int32
251 func semasleep1(ns
int64) int32 {
256 secs
:= timediv(ns
, 1000000000, &nsecs
)
257 r
:= mach_semaphore_timedwait(_g_
.m
.mos
.waitsema
, uint32(secs
), uint32(nsecs
))
258 if r
== _KERN_ABORTED || r
== _KERN_OPERATION_TIMED_OUT
{
262 macherror(r
, "semaphore_wait")
268 r
:= mach_semaphore_wait(_g_
.m
.mos
.waitsema
)
272 // Note: We don't know how this call (with no timeout) can get _KERN_OPERATION_TIMED_OUT,
273 // but it does reliably, though at a very low rate, on OS X 10.8, 10.9, 10.10, and 10.11.
274 // See golang.org/issue/17161.
275 if r
== _KERN_ABORTED || r
== _KERN_OPERATION_TIMED_OUT
{ // interrupted
278 macherror(r
, "semaphore_wait")
284 func semasleep(ns
int64) int32 {
293 func mach_semrelease(sem
uint32) {
295 r
:= mach_semaphore_signal(sem
)
299 if r
== _KERN_ABORTED
{ // interrupted
303 // mach_semrelease must be completely nosplit,
304 // because it is called from Go code.
305 // If we're going to die, start that process on the system stack
306 // to avoid a Go stack split.
307 systemstack(func() { macherror(r
, "semaphore_signal") })
311 type machheader
struct {
314 msgh_remote_port
uint32
315 msgh_local_port
uint32
320 type machndr
struct {