blob: e9b5c20b2aa504f9f54360616e3663f283f5cdcf [file] [log] [blame]
Rob Pikeaeb43982008-06-21 15:36:23 -07001// 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
5#include "runtime.h"
Russ Cox878822f2009-03-24 13:06:51 -07006#include "defs.h"
7#include "signals.h"
Rob Pike7b210c52008-06-23 16:34:17 -07008
Robert Griesemer206daea2008-06-24 16:48:54 -07009typedef uint64 __uint64_t;
10
Robert Griesemer3311e1b2008-06-25 17:07:22 -070011/* From /usr/include/mach/i386/_structs.h */
Robert Griesemer206daea2008-06-24 16:48:54 -070012#define _STRUCT_X86_THREAD_STATE64 struct __darwin_x86_thread_state64
13_STRUCT_X86_THREAD_STATE64
14{
15 __uint64_t __rax;
16 __uint64_t __rbx;
17 __uint64_t __rcx;
18 __uint64_t __rdx;
19 __uint64_t __rdi;
20 __uint64_t __rsi;
21 __uint64_t __rbp;
22 __uint64_t __rsp;
23 __uint64_t __r8;
24 __uint64_t __r9;
25 __uint64_t __r10;
26 __uint64_t __r11;
27 __uint64_t __r12;
28 __uint64_t __r13;
29 __uint64_t __r14;
30 __uint64_t __r15;
31 __uint64_t __rip;
32 __uint64_t __rflags;
33 __uint64_t __cs;
34 __uint64_t __fs;
35 __uint64_t __gs;
36};
37
38
39void
40print_thread_state(_STRUCT_X86_THREAD_STATE64* ss)
41{
Russ Coxefc86a72008-11-25 16:48:10 -080042 prints("\nrax "); sys·printhex(ss->__rax);
43 prints("\nrbx "); sys·printhex(ss->__rbx);
44 prints("\nrcx "); sys·printhex(ss->__rcx);
45 prints("\nrdx "); sys·printhex(ss->__rdx);
46 prints("\nrdi "); sys·printhex(ss->__rdi);
47 prints("\nrsi "); sys·printhex(ss->__rsi);
48 prints("\nrbp "); sys·printhex(ss->__rbp);
49 prints("\nrsp "); sys·printhex(ss->__rsp);
50 prints("\nr8 "); sys·printhex(ss->__r8 );
51 prints("\nr9 "); sys·printhex(ss->__r9 );
52 prints("\nr10 "); sys·printhex(ss->__r10);
53 prints("\nr11 "); sys·printhex(ss->__r11);
54 prints("\nr12 "); sys·printhex(ss->__r12);
55 prints("\nr13 "); sys·printhex(ss->__r13);
56 prints("\nr14 "); sys·printhex(ss->__r14);
57 prints("\nr15 "); sys·printhex(ss->__r15);
58 prints("\nrip "); sys·printhex(ss->__rip);
59 prints("\nrflags "); sys·printhex(ss->__rflags);
60 prints("\ncs "); sys·printhex(ss->__cs);
61 prints("\nfs "); sys·printhex(ss->__fs);
62 prints("\ngs "); sys·printhex(ss->__gs);
Robert Griesemer206daea2008-06-24 16:48:54 -070063 prints("\n");
64}
65
66
Robert Griesemer3311e1b2008-06-25 17:07:22 -070067/* Code generated via: g++ -m64 gen_signals_support.cc && a.out */
Robert Griesemer206daea2008-06-24 16:48:54 -070068
69static void *adr_at(void *ptr, int32 offs) {
70 return (void *)((uint8 *)ptr + offs);
71}
72
73static void *ptr_at(void *ptr, int32 offs) {
74 return *(void **)((uint8 *)ptr + offs);
75}
76
77typedef void ucontext_t;
78typedef void _STRUCT_MCONTEXT64;
79typedef void _STRUCT_X86_EXCEPTION_STATE64;
80typedef void _STRUCT_X86_FLOAT_STATE64;
81
82static _STRUCT_MCONTEXT64 *get_uc_mcontext(ucontext_t *ptr) {
83 return (_STRUCT_MCONTEXT64 *)ptr_at(ptr, 48);
84}
85
86static _STRUCT_X86_EXCEPTION_STATE64 *get___es(_STRUCT_MCONTEXT64 *ptr) {
87 return (_STRUCT_X86_EXCEPTION_STATE64 *)adr_at(ptr, 0);
88}
89
90static _STRUCT_X86_THREAD_STATE64 *get___ss(_STRUCT_MCONTEXT64 *ptr) {
91 return (_STRUCT_X86_THREAD_STATE64 *)adr_at(ptr, 16);
92}
93
94static _STRUCT_X86_FLOAT_STATE64 *get___fs(_STRUCT_MCONTEXT64 *ptr) {
95 return (_STRUCT_X86_FLOAT_STATE64 *)adr_at(ptr, 184);
96}
97
98/* End of generated code */
99
100
Rob Pike7b210c52008-06-23 16:34:17 -0700101/*
102 * This assembler routine takes the args from registers, puts them on the stack,
Russ Coxdfa58932008-12-03 14:21:28 -0800103 * and calls the registered handler.
Rob Pike7b210c52008-06-23 16:34:17 -0700104 */
Russ Coxdfa58932008-12-03 14:21:28 -0800105extern void sigtramp(void);
Rob Pike7b210c52008-06-23 16:34:17 -0700106/*
107 * Rudimentary reverse-engineered definition of signal interface.
108 * You'd think it would be documented.
109 */
Russ Coxdfa58932008-12-03 14:21:28 -0800110struct siginfo {
Rob Pike7b210c52008-06-23 16:34:17 -0700111 int32 si_signo; /* signal number */
112 int32 si_errno; /* errno association */
113 int32 si_code; /* signal code */
114 int32 si_pid; /* sending process */
115 int32 si_uid; /* sender's ruid */
116 int32 si_status; /* exit value */
117 void *si_addr; /* faulting address */
118 /* more stuff here */
Russ Coxdfa58932008-12-03 14:21:28 -0800119};
Rob Pike7b210c52008-06-23 16:34:17 -0700120
Russ Coxdfa58932008-12-03 14:21:28 -0800121struct sigaction {
122 void (*sa_handler)(int32, struct siginfo*, void*); // actual handler
123 void (*sa_trampoline)(void); // assembly trampoline
124 uint32 sa_mask; // signal mask during handler
125 int32 sa_flags; // flags below
126};
Rob Pike7b210c52008-06-23 16:34:17 -0700127
128void
Russ Coxdfa58932008-12-03 14:21:28 -0800129sighandler(int32 sig, struct siginfo *info, void *context)
Robert Griesemer206daea2008-06-24 16:48:54 -0700130{
Rob Pike6e8dbc22008-09-12 09:44:41 -0700131 if(panicking) // traceback already printed
Russ Cox36096242009-01-16 14:58:14 -0800132 sys_Exit(2);
Russ Cox1ce17912009-01-26 17:37:05 -0800133 panicking = 1;
Rob Piked4c2da42008-06-23 20:12:39 -0700134
Robert Griesemer206daea2008-06-24 16:48:54 -0700135 _STRUCT_MCONTEXT64 *uc_mcontext = get_uc_mcontext(context);
136 _STRUCT_X86_THREAD_STATE64 *ss = get___ss(uc_mcontext);
137
Rob Pikec1ad0502008-09-13 13:13:36 -0700138 if(sig < 0 || sig >= NSIG){
139 prints("Signal ");
140 sys·printint(sig);
141 }else{
142 prints(sigtab[sig].name);
Rob Pike6e8dbc22008-09-12 09:44:41 -0700143 }
144
Russ Coxefc86a72008-11-25 16:48:10 -0800145 prints("\nFaulting address: "); sys·printpointer(info->si_addr);
146 prints("\npc: "); sys·printhex(ss->__rip);
Rob Piked3204ef2008-06-30 14:39:47 -0700147 prints("\n\n");
Russ Coxf7f63292008-08-05 14:21:42 -0700148
Russ Coxfb40f882008-09-22 13:47:53 -0700149 if(gotraceback()){
150 traceback((void *)ss->__rip, (void *)ss->__rsp, (void*)ss->__r15);
151 tracebackothers((void*)ss->__r15);
152 print_thread_state(ss);
153 }
Russ Coxf7f63292008-08-05 14:21:42 -0700154
Russ Cox36096242009-01-16 14:58:14 -0800155 sys_Exit(2);
Rob Pike7b210c52008-06-23 16:34:17 -0700156}
157
Russ Coxdfa58932008-12-03 14:21:28 -0800158void
159sigignore(int32, struct siginfo*, void*)
160{
161}
162
Russ Coxa67258f2008-09-18 15:56:46 -0700163struct stack_t {
164 byte *sp;
165 int64 size;
166 int32 flags;
167};
Robert Griesemer3311e1b2008-06-25 17:07:22 -0700168
Rob Pikeaeb43982008-06-21 15:36:23 -0700169void
Russ Coxa67258f2008-09-18 15:56:46 -0700170signalstack(byte *p, int32 n)
171{
172 struct stack_t st;
173
174 st.sp = p;
175 st.size = n;
176 st.flags = 0;
177 sigaltstack(&st, nil);
178}
179
Russ Coxdfa58932008-12-03 14:21:28 -0800180void sigaction(int64, void*, void*);
181
182enum {
183 SA_SIGINFO = 0x40,
184 SA_RESTART = 0x02,
185 SA_ONSTACK = 0x01,
186 SA_USERTRAMP = 0x100,
187 SA_64REGSET = 0x200,
188};
189
Russ Coxa67258f2008-09-18 15:56:46 -0700190void
Rob Pikeaeb43982008-06-21 15:36:23 -0700191initsig(void)
192{
Rob Pike7b210c52008-06-23 16:34:17 -0700193 int32 i;
Russ Coxdfa58932008-12-03 14:21:28 -0800194 static struct sigaction sa;
Russ Coxa67258f2008-09-18 15:56:46 -0700195
Russ Coxdfa58932008-12-03 14:21:28 -0800196 sa.sa_flags |= SA_SIGINFO|SA_ONSTACK;
197 sa.sa_mask = 0; // 0xFFFFFFFFU;
198 sa.sa_trampoline = sigtramp;
199 for(i = 0; i<NSIG; i++) {
200 if(sigtab[i].flags) {
201 if(sigtab[i].flags & SigCatch) {
202 sa.sa_handler = sighandler;
203 } else {
204 sa.sa_handler = sigignore;
205 }
206 if(sigtab[i].flags & SigRestart)
207 sa.sa_flags |= SA_RESTART;
208 else
209 sa.sa_flags &= ~SA_RESTART;
210 sigaction(i, &sa, nil);
Rob Pike7b210c52008-06-23 16:34:17 -0700211 }
Russ Coxdfa58932008-12-03 14:21:28 -0800212 }
Rob Pikeaeb43982008-06-21 15:36:23 -0700213}
Russ Coxd28acc42008-08-04 16:43:49 -0700214
215static void
216unimplemented(int8 *name)
217{
218 prints(name);
219 prints(" not implemented\n");
220 *(int32*)1231 = 1231;
221}
222
Russ Cox376898c2008-09-09 11:50:14 -0700223// Thread-safe allocation of a semaphore.
224// Psema points at a kernel semaphore key.
225// It starts out zero, meaning no semaphore.
226// Fill it in, being careful of others calling initsema
227// simultaneously.
228static void
229initsema(uint32 *psema)
230{
231 uint32 sema;
232
233 if(*psema != 0) // already have one
234 return;
235
Russ Cox1f8a40d2009-01-22 16:23:44 -0800236 sema = mach_semcreate();
Russ Cox376898c2008-09-09 11:50:14 -0700237 if(!cas(psema, 0, sema)){
238 // Someone else filled it in. Use theirs.
Russ Cox1f8a40d2009-01-22 16:23:44 -0800239 mach_semdestroy(sema);
Russ Cox376898c2008-09-09 11:50:14 -0700240 return;
241 }
242}
243
244
245// Atomic add and return new value.
246static uint32
247xadd(uint32 volatile *val, int32 delta)
248{
249 uint32 oval, nval;
250
251 for(;;){
252 oval = *val;
253 nval = oval + delta;
254 if(cas(val, oval, nval))
255 return nval;
256 }
257}
258
259
260// Blocking locks.
261
262// Implement Locks, using semaphores.
263// l->key is the number of threads who want the lock.
264// In a race, one thread increments l->key from 0 to 1
265// and the others increment it from >0 to >1. The thread
266// who does the 0->1 increment gets the lock, and the
267// others wait on the semaphore. When the 0->1 thread
268// releases the lock by decrementing l->key, l->key will
269// be >0, so it will increment the semaphore to wake up
270// one of the others. This is the same algorithm used
Russ Cox5ff12f82008-09-24 10:25:28 -0700271// in Plan 9's user-level locks.
Russ Cox376898c2008-09-09 11:50:14 -0700272//
273// Note that semaphores are never destroyed (the kernel
274// will clean up when the process exits). We assume for now
275// that Locks are only used for long-lived structures like M and G.
276
Russ Coxd28acc42008-08-04 16:43:49 -0700277void
278lock(Lock *l)
279{
Russ Cox53e69e12009-01-27 14:01:20 -0800280 if(m->locks < 0)
281 throw("lock count");
282 m->locks++;
283
Russ Cox376898c2008-09-09 11:50:14 -0700284 // Allocate semaphore if needed.
285 if(l->sema == 0)
286 initsema(&l->sema);
287
288 if(xadd(&l->key, 1) > 1) // someone else has it; wait
Russ Cox1f8a40d2009-01-22 16:23:44 -0800289 mach_semacquire(l->sema);
Russ Coxd28acc42008-08-04 16:43:49 -0700290}
291
292void
293unlock(Lock *l)
294{
Russ Cox1ce17912009-01-26 17:37:05 -0800295 m->locks--;
Russ Cox53e69e12009-01-27 14:01:20 -0800296 if(m->locks < 0)
297 throw("lock count");
298
Russ Cox376898c2008-09-09 11:50:14 -0700299 if(xadd(&l->key, -1) > 0) // someone else is waiting
Russ Cox1f8a40d2009-01-22 16:23:44 -0800300 mach_semrelease(l->sema);
Russ Coxd28acc42008-08-04 16:43:49 -0700301}
302
Russ Cox376898c2008-09-09 11:50:14 -0700303
Russ Cox5ff12f82008-09-24 10:25:28 -0700304// User-level semaphore implementation:
305// try to do the operations in user space on u,
306// but when it's time to block, fall back on the kernel semaphore k.
307// This is the same algorithm used in Plan 9.
308void
309usemacquire(Usema *s)
310{
311 if((int32)xadd(&s->u, -1) < 0)
Russ Cox1f8a40d2009-01-22 16:23:44 -0800312 mach_semacquire(s->k);
Russ Cox5ff12f82008-09-24 10:25:28 -0700313}
314
315void
316usemrelease(Usema *s)
317{
318 if((int32)xadd(&s->u, 1) <= 0)
Russ Cox1f8a40d2009-01-22 16:23:44 -0800319 mach_semrelease(s->k);
Russ Cox5ff12f82008-09-24 10:25:28 -0700320}
321
322
Russ Cox376898c2008-09-09 11:50:14 -0700323// Event notifications.
Russ Coxd28acc42008-08-04 16:43:49 -0700324void
Russ Cox96824002008-08-05 14:18:47 -0700325noteclear(Note *n)
Russ Coxd28acc42008-08-04 16:43:49 -0700326{
Russ Cox376898c2008-09-09 11:50:14 -0700327 n->wakeup = 0;
Russ Coxd28acc42008-08-04 16:43:49 -0700328}
329
330void
Russ Cox96824002008-08-05 14:18:47 -0700331notesleep(Note *n)
Russ Coxd28acc42008-08-04 16:43:49 -0700332{
Russ Cox5ff12f82008-09-24 10:25:28 -0700333 if(n->sema.k == 0)
334 initsema(&n->sema.k);
Russ Cox376898c2008-09-09 11:50:14 -0700335 while(!n->wakeup)
Russ Cox5ff12f82008-09-24 10:25:28 -0700336 usemacquire(&n->sema);
Russ Coxd28acc42008-08-04 16:43:49 -0700337}
338
339void
Russ Cox96824002008-08-05 14:18:47 -0700340notewakeup(Note *n)
Russ Coxd28acc42008-08-04 16:43:49 -0700341{
Russ Cox5ff12f82008-09-24 10:25:28 -0700342 if(n->sema.k == 0)
343 initsema(&n->sema.k);
Russ Cox376898c2008-09-09 11:50:14 -0700344 n->wakeup = 1;
Russ Cox5ff12f82008-09-24 10:25:28 -0700345 usemrelease(&n->sema);
Russ Cox376898c2008-09-09 11:50:14 -0700346}
347
348
349// BSD interface for threading.
350void
351osinit(void)
352{
353 // Register our thread-creation callback (see sys_amd64_darwin.s).
354 bsdthread_register();
Russ Coxd28acc42008-08-04 16:43:49 -0700355}
356
357void
Russ Cox376898c2008-09-09 11:50:14 -0700358newosproc(M *m, G *g, void *stk, void (*fn)(void))
Russ Coxd28acc42008-08-04 16:43:49 -0700359{
Russ Cox376898c2008-09-09 11:50:14 -0700360 bsdthread_create(stk, m, g, fn);
Russ Coxd28acc42008-08-04 16:43:49 -0700361}
362
Russ Coxa67258f2008-09-18 15:56:46 -0700363// Called to initialize a new m (including the bootstrap m).
364void
365minit(void)
366{
367 // Initialize signal handling.
368 m->gsignal = malg(32*1024); // OS X wants >=8K, Linux >=2K
369 signalstack(m->gsignal->stackguard, 32*1024);
370}
371
Russ Cox376898c2008-09-09 11:50:14 -0700372
373// Mach IPC, to get at semaphores
374// Definitions are in /usr/include/mach on a Mac.
375
376static void
377macherror(kern_return_t r, int8 *fn)
Russ Coxd28acc42008-08-04 16:43:49 -0700378{
Russ Cox376898c2008-09-09 11:50:14 -0700379 prints("mach error ");
380 prints(fn);
381 prints(": ");
382 sys·printint(r);
383 prints("\n");
384 throw("mach error");
385}
386
387enum
388{
389 DebugMach = 0
390};
391
392typedef int32 mach_msg_option_t;
393typedef uint32 mach_msg_bits_t;
394typedef uint32 mach_msg_id_t;
395typedef uint32 mach_msg_size_t;
396typedef uint32 mach_msg_timeout_t;
397typedef uint32 mach_port_name_t;
398typedef uint64 mach_vm_address_t;
399
400typedef struct mach_msg_header_t mach_msg_header_t;
401typedef struct mach_msg_body_t mach_msg_body_t;
402typedef struct mach_msg_port_descriptor_t mach_msg_port_descriptor_t;
403typedef struct NDR_record_t NDR_record_t;
404
405enum
406{
407 MACH_MSG_TYPE_MOVE_RECEIVE = 16,
408 MACH_MSG_TYPE_MOVE_SEND = 17,
409 MACH_MSG_TYPE_MOVE_SEND_ONCE = 18,
410 MACH_MSG_TYPE_COPY_SEND = 19,
411 MACH_MSG_TYPE_MAKE_SEND = 20,
412 MACH_MSG_TYPE_MAKE_SEND_ONCE = 21,
413 MACH_MSG_TYPE_COPY_RECEIVE = 22,
414
415 MACH_MSG_PORT_DESCRIPTOR = 0,
416 MACH_MSG_OOL_DESCRIPTOR = 1,
417 MACH_MSG_OOL_PORTS_DESCRIPTOR = 2,
418 MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 3,
419
420 MACH_MSGH_BITS_COMPLEX = 0x80000000,
421
422 MACH_SEND_MSG = 1,
423 MACH_RCV_MSG = 2,
424 MACH_RCV_LARGE = 4,
425
426 MACH_SEND_TIMEOUT = 0x10,
427 MACH_SEND_INTERRUPT = 0x40,
428 MACH_SEND_CANCEL = 0x80,
429 MACH_SEND_ALWAYS = 0x10000,
430 MACH_SEND_TRAILER = 0x20000,
431 MACH_RCV_TIMEOUT = 0x100,
432 MACH_RCV_NOTIFY = 0x200,
433 MACH_RCV_INTERRUPT = 0x400,
434 MACH_RCV_OVERWRITE = 0x1000,
435};
436
437mach_port_t mach_task_self(void);
438mach_port_t mach_thread_self(void);
439
440#pragma pack on
441struct mach_msg_header_t
442{
443 mach_msg_bits_t bits;
444 mach_msg_size_t size;
445 mach_port_t remote_port;
446 mach_port_t local_port;
447 mach_msg_size_t reserved;
448 mach_msg_id_t id;
449};
450
451struct mach_msg_body_t
452{
453 uint32 descriptor_count;
454};
455
456struct mach_msg_port_descriptor_t
457{
458 mach_port_t name;
459 uint32 pad1;
460 uint16 pad2;
461 uint8 disposition;
462 uint8 type;
463};
464
465enum
466{
467 NDR_PROTOCOL_2_0 = 0,
468 NDR_INT_BIG_ENDIAN = 0,
469 NDR_INT_LITTLE_ENDIAN = 1,
470 NDR_FLOAT_IEEE = 0,
471 NDR_CHAR_ASCII = 0
472};
473
474struct NDR_record_t
475{
476 uint8 mig_vers;
477 uint8 if_vers;
478 uint8 reserved1;
479 uint8 mig_encoding;
480 uint8 int_rep;
481 uint8 char_rep;
482 uint8 float_rep;
483 uint8 reserved2;
484};
485#pragma pack off
486
487static NDR_record_t zerondr;
488
489#define MACH_MSGH_BITS(a, b) ((a) | ((b)<<8))
490
491// Mach system calls (in sys_amd64_darwin.s)
492kern_return_t mach_msg_trap(mach_msg_header_t*,
493 mach_msg_option_t, mach_msg_size_t, mach_msg_size_t,
494 mach_port_name_t, mach_msg_timeout_t, mach_port_name_t);
495mach_port_t mach_reply_port(void);
496mach_port_t mach_task_self(void);
497mach_port_t mach_thread_self(void);
498
499static kern_return_t
500mach_msg(mach_msg_header_t *h,
501 mach_msg_option_t op,
502 mach_msg_size_t send_size,
503 mach_msg_size_t rcv_size,
504 mach_port_name_t rcv_name,
505 mach_msg_timeout_t timeout,
506 mach_port_name_t notify)
507{
508 // TODO: Loop on interrupt.
509 return mach_msg_trap(h, op, send_size, rcv_size, rcv_name, timeout, notify);
510}
511
512
513// Mach RPC (MIG)
514// I'm not using the Mach names anymore. They're too long.
515
516enum
517{
518 MinMachMsg = 48,
519 Reply = 100,
520};
521
522#pragma pack on
523typedef struct CodeMsg CodeMsg;
524struct CodeMsg
525{
526 mach_msg_header_t h;
527 NDR_record_t NDR;
528 kern_return_t code;
529};
530#pragma pack off
531
532static kern_return_t
533machcall(mach_msg_header_t *h, int32 maxsize, int32 rxsize)
534{
535 uint32 *p;
536 int32 i, ret, id;
537 mach_port_t port;
538 CodeMsg *c;
539
540 if((port = m->machport) == 0){
541 port = mach_reply_port();
542 m->machport = port;
543 }
544
545 h->bits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
546 h->local_port = port;
547 h->reserved = 0;
548 id = h->id;
549
550 if(DebugMach){
551 p = (uint32*)h;
552 prints("send:\t");
553 for(i=0; i<h->size/sizeof(p[0]); i++){
554 prints(" ");
555 sys·printpointer((void*)p[i]);
556 if(i%8 == 7)
557 prints("\n\t");
558 }
559 if(i%8)
560 prints("\n");
561 }
562
563 ret = mach_msg(h, MACH_SEND_MSG|MACH_RCV_MSG,
564 h->size, maxsize, port, 0, 0);
565 if(ret != 0){
566 if(DebugMach){
567 prints("mach_msg error ");
568 sys·printint(ret);
569 prints("\n");
570 }
571 return ret;
572 }
573
574 if(DebugMach){
575 p = (uint32*)h;
576 prints("recv:\t");
577 for(i=0; i<h->size/sizeof(p[0]); i++){
578 prints(" ");
579 sys·printpointer((void*)p[i]);
580 if(i%8 == 7)
581 prints("\n\t");
582 }
583 if(i%8)
584 prints("\n");
585 }
586
587 if(h->id != id+Reply){
588 if(DebugMach){
589 prints("mach_msg reply id mismatch ");
590 sys·printint(h->id);
591 prints(" != ");
592 sys·printint(id+Reply);
593 prints("\n");
594 }
595 return -303; // MIG_REPLY_MISMATCH
596 }
597
598 // Look for a response giving the return value.
599 // Any call can send this back with an error,
600 // and some calls only have return values so they
601 // send it back on success too. I don't quite see how
602 // you know it's one of these and not the full response
603 // format, so just look if the message is right.
604 c = (CodeMsg*)h;
605 if(h->size == sizeof(CodeMsg)
606 && !(h->bits & MACH_MSGH_BITS_COMPLEX)){
607 if(DebugMach){
608 prints("mig result ");
609 sys·printint(c->code);
610 prints("\n");
611 }
612 return c->code;
613 }
614
615 if(h->size != rxsize){
616 if(DebugMach){
617 prints("mach_msg reply size mismatch ");
618 sys·printint(h->size);
619 prints(" != ");
620 sys·printint(rxsize);
621 prints("\n");
622 }
623 return -307; // MIG_ARRAY_TOO_LARGE
624 }
625
Russ Coxd28acc42008-08-04 16:43:49 -0700626 return 0;
627}
Russ Cox376898c2008-09-09 11:50:14 -0700628
629
630// Semaphores!
631
632enum
633{
Russ Cox1f8a40d2009-01-22 16:23:44 -0800634 Tmach_semcreate = 3418,
635 Rmach_semcreate = Tmach_semcreate + Reply,
Russ Cox376898c2008-09-09 11:50:14 -0700636
Russ Cox1f8a40d2009-01-22 16:23:44 -0800637 Tmach_semdestroy = 3419,
638 Rmach_semdestroy = Tmach_semdestroy + Reply,
Russ Cox376898c2008-09-09 11:50:14 -0700639};
640
Russ Cox1f8a40d2009-01-22 16:23:44 -0800641typedef struct Tmach_semcreateMsg Tmach_semcreateMsg;
642typedef struct Rmach_semcreateMsg Rmach_semcreateMsg;
643typedef struct Tmach_semdestroyMsg Tmach_semdestroyMsg;
644// Rmach_semdestroyMsg = CodeMsg
Russ Cox376898c2008-09-09 11:50:14 -0700645
646#pragma pack on
Russ Cox1f8a40d2009-01-22 16:23:44 -0800647struct Tmach_semcreateMsg
Russ Cox376898c2008-09-09 11:50:14 -0700648{
649 mach_msg_header_t h;
650 NDR_record_t ndr;
651 int32 policy;
652 int32 value;
653};
654
Russ Cox1f8a40d2009-01-22 16:23:44 -0800655struct Rmach_semcreateMsg
Russ Cox376898c2008-09-09 11:50:14 -0700656{
657 mach_msg_header_t h;
658 mach_msg_body_t body;
659 mach_msg_port_descriptor_t semaphore;
660};
661
Russ Cox1f8a40d2009-01-22 16:23:44 -0800662struct Tmach_semdestroyMsg
Russ Cox376898c2008-09-09 11:50:14 -0700663{
664 mach_msg_header_t h;
665 mach_msg_body_t body;
666 mach_msg_port_descriptor_t semaphore;
667};
668#pragma pack off
669
670mach_port_t
Russ Cox1f8a40d2009-01-22 16:23:44 -0800671mach_semcreate(void)
Russ Cox376898c2008-09-09 11:50:14 -0700672{
673 union {
Russ Cox1f8a40d2009-01-22 16:23:44 -0800674 Tmach_semcreateMsg tx;
675 Rmach_semcreateMsg rx;
Russ Cox376898c2008-09-09 11:50:14 -0700676 uint8 pad[MinMachMsg];
677 } m;
678 kern_return_t r;
679
680 m.tx.h.bits = 0;
681 m.tx.h.size = sizeof(m.tx);
682 m.tx.h.remote_port = mach_task_self();
Russ Cox1f8a40d2009-01-22 16:23:44 -0800683 m.tx.h.id = Tmach_semcreate;
Russ Cox376898c2008-09-09 11:50:14 -0700684 m.tx.ndr = zerondr;
685
686 m.tx.policy = 0; // 0 = SYNC_POLICY_FIFO
687 m.tx.value = 0;
688
689 if((r = machcall(&m.tx.h, sizeof m, sizeof(m.rx))) != 0)
690 macherror(r, "semaphore_create");
691 if(m.rx.body.descriptor_count != 1)
Russ Cox1f8a40d2009-01-22 16:23:44 -0800692 unimplemented("mach_semcreate desc count");
Russ Cox376898c2008-09-09 11:50:14 -0700693 return m.rx.semaphore.name;
694}
695
696void
Russ Cox1f8a40d2009-01-22 16:23:44 -0800697mach_semdestroy(mach_port_t sem)
Russ Cox376898c2008-09-09 11:50:14 -0700698{
699 union {
Russ Cox1f8a40d2009-01-22 16:23:44 -0800700 Tmach_semdestroyMsg tx;
Russ Cox376898c2008-09-09 11:50:14 -0700701 uint8 pad[MinMachMsg];
702 } m;
703 kern_return_t r;
704
705 m.tx.h.bits = MACH_MSGH_BITS_COMPLEX;
706 m.tx.h.size = sizeof(m.tx);
707 m.tx.h.remote_port = mach_task_self();
Russ Cox1f8a40d2009-01-22 16:23:44 -0800708 m.tx.h.id = Tmach_semdestroy;
Russ Cox376898c2008-09-09 11:50:14 -0700709 m.tx.body.descriptor_count = 1;
710 m.tx.semaphore.name = sem;
711 m.tx.semaphore.disposition = MACH_MSG_TYPE_MOVE_SEND;
712 m.tx.semaphore.type = 0;
713
714 if((r = machcall(&m.tx.h, sizeof m, 0)) != 0)
715 macherror(r, "semaphore_destroy");
716}
717
718// The other calls have simple system call traps
719// in sys_amd64_darwin.s
720kern_return_t mach_semaphore_wait(uint32 sema);
721kern_return_t mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec);
722kern_return_t mach_semaphore_signal(uint32 sema);
723kern_return_t mach_semaphore_signal_all(uint32 sema);
724
725void
Russ Cox1f8a40d2009-01-22 16:23:44 -0800726mach_semacquire(mach_port_t sem)
Russ Cox376898c2008-09-09 11:50:14 -0700727{
728 kern_return_t r;
729
730 if((r = mach_semaphore_wait(sem)) != 0)
731 macherror(r, "semaphore_wait");
732}
733
734void
Russ Cox1f8a40d2009-01-22 16:23:44 -0800735mach_semrelease(mach_port_t sem)
Russ Cox376898c2008-09-09 11:50:14 -0700736{
737 kern_return_t r;
738
739 if((r = mach_semaphore_signal(sem)) != 0)
740 macherror(r, "semaphore_signal");
741}
742