Rob Pike | aeb4398 | 2008-06-21 15:36:23 -0700 | [diff] [blame] | 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. |
| 4 | |
| 5 | #include "runtime.h" |
Russ Cox | 878822f | 2009-03-24 13:06:51 -0700 | [diff] [blame^] | 6 | #include "defs.h" |
| 7 | #include "signals.h" |
Rob Pike | 7b210c5 | 2008-06-23 16:34:17 -0700 | [diff] [blame] | 8 | |
Robert Griesemer | 206daea | 2008-06-24 16:48:54 -0700 | [diff] [blame] | 9 | typedef uint64 __uint64_t; |
| 10 | |
Robert Griesemer | 3311e1b | 2008-06-25 17:07:22 -0700 | [diff] [blame] | 11 | /* From /usr/include/mach/i386/_structs.h */ |
Robert Griesemer | 206daea | 2008-06-24 16:48:54 -0700 | [diff] [blame] | 12 | #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 | |
| 39 | void |
| 40 | print_thread_state(_STRUCT_X86_THREAD_STATE64* ss) |
| 41 | { |
Russ Cox | efc86a7 | 2008-11-25 16:48:10 -0800 | [diff] [blame] | 42 | 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 Griesemer | 206daea | 2008-06-24 16:48:54 -0700 | [diff] [blame] | 63 | prints("\n"); |
| 64 | } |
| 65 | |
| 66 | |
Robert Griesemer | 3311e1b | 2008-06-25 17:07:22 -0700 | [diff] [blame] | 67 | /* Code generated via: g++ -m64 gen_signals_support.cc && a.out */ |
Robert Griesemer | 206daea | 2008-06-24 16:48:54 -0700 | [diff] [blame] | 68 | |
| 69 | static void *adr_at(void *ptr, int32 offs) { |
| 70 | return (void *)((uint8 *)ptr + offs); |
| 71 | } |
| 72 | |
| 73 | static void *ptr_at(void *ptr, int32 offs) { |
| 74 | return *(void **)((uint8 *)ptr + offs); |
| 75 | } |
| 76 | |
| 77 | typedef void ucontext_t; |
| 78 | typedef void _STRUCT_MCONTEXT64; |
| 79 | typedef void _STRUCT_X86_EXCEPTION_STATE64; |
| 80 | typedef void _STRUCT_X86_FLOAT_STATE64; |
| 81 | |
| 82 | static _STRUCT_MCONTEXT64 *get_uc_mcontext(ucontext_t *ptr) { |
| 83 | return (_STRUCT_MCONTEXT64 *)ptr_at(ptr, 48); |
| 84 | } |
| 85 | |
| 86 | static _STRUCT_X86_EXCEPTION_STATE64 *get___es(_STRUCT_MCONTEXT64 *ptr) { |
| 87 | return (_STRUCT_X86_EXCEPTION_STATE64 *)adr_at(ptr, 0); |
| 88 | } |
| 89 | |
| 90 | static _STRUCT_X86_THREAD_STATE64 *get___ss(_STRUCT_MCONTEXT64 *ptr) { |
| 91 | return (_STRUCT_X86_THREAD_STATE64 *)adr_at(ptr, 16); |
| 92 | } |
| 93 | |
| 94 | static _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 Pike | 7b210c5 | 2008-06-23 16:34:17 -0700 | [diff] [blame] | 101 | /* |
| 102 | * This assembler routine takes the args from registers, puts them on the stack, |
Russ Cox | dfa5893 | 2008-12-03 14:21:28 -0800 | [diff] [blame] | 103 | * and calls the registered handler. |
Rob Pike | 7b210c5 | 2008-06-23 16:34:17 -0700 | [diff] [blame] | 104 | */ |
Russ Cox | dfa5893 | 2008-12-03 14:21:28 -0800 | [diff] [blame] | 105 | extern void sigtramp(void); |
Rob Pike | 7b210c5 | 2008-06-23 16:34:17 -0700 | [diff] [blame] | 106 | /* |
| 107 | * Rudimentary reverse-engineered definition of signal interface. |
| 108 | * You'd think it would be documented. |
| 109 | */ |
Russ Cox | dfa5893 | 2008-12-03 14:21:28 -0800 | [diff] [blame] | 110 | struct siginfo { |
Rob Pike | 7b210c5 | 2008-06-23 16:34:17 -0700 | [diff] [blame] | 111 | 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 Cox | dfa5893 | 2008-12-03 14:21:28 -0800 | [diff] [blame] | 119 | }; |
Rob Pike | 7b210c5 | 2008-06-23 16:34:17 -0700 | [diff] [blame] | 120 | |
Russ Cox | dfa5893 | 2008-12-03 14:21:28 -0800 | [diff] [blame] | 121 | struct 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 Pike | 7b210c5 | 2008-06-23 16:34:17 -0700 | [diff] [blame] | 127 | |
| 128 | void |
Russ Cox | dfa5893 | 2008-12-03 14:21:28 -0800 | [diff] [blame] | 129 | sighandler(int32 sig, struct siginfo *info, void *context) |
Robert Griesemer | 206daea | 2008-06-24 16:48:54 -0700 | [diff] [blame] | 130 | { |
Rob Pike | 6e8dbc2 | 2008-09-12 09:44:41 -0700 | [diff] [blame] | 131 | if(panicking) // traceback already printed |
Russ Cox | 3609624 | 2009-01-16 14:58:14 -0800 | [diff] [blame] | 132 | sys_Exit(2); |
Russ Cox | 1ce1791 | 2009-01-26 17:37:05 -0800 | [diff] [blame] | 133 | panicking = 1; |
Rob Pike | d4c2da4 | 2008-06-23 20:12:39 -0700 | [diff] [blame] | 134 | |
Robert Griesemer | 206daea | 2008-06-24 16:48:54 -0700 | [diff] [blame] | 135 | _STRUCT_MCONTEXT64 *uc_mcontext = get_uc_mcontext(context); |
| 136 | _STRUCT_X86_THREAD_STATE64 *ss = get___ss(uc_mcontext); |
| 137 | |
Rob Pike | c1ad050 | 2008-09-13 13:13:36 -0700 | [diff] [blame] | 138 | if(sig < 0 || sig >= NSIG){ |
| 139 | prints("Signal "); |
| 140 | sys·printint(sig); |
| 141 | }else{ |
| 142 | prints(sigtab[sig].name); |
Rob Pike | 6e8dbc2 | 2008-09-12 09:44:41 -0700 | [diff] [blame] | 143 | } |
| 144 | |
Russ Cox | efc86a7 | 2008-11-25 16:48:10 -0800 | [diff] [blame] | 145 | prints("\nFaulting address: "); sys·printpointer(info->si_addr); |
| 146 | prints("\npc: "); sys·printhex(ss->__rip); |
Rob Pike | d3204ef | 2008-06-30 14:39:47 -0700 | [diff] [blame] | 147 | prints("\n\n"); |
Russ Cox | f7f6329 | 2008-08-05 14:21:42 -0700 | [diff] [blame] | 148 | |
Russ Cox | fb40f88 | 2008-09-22 13:47:53 -0700 | [diff] [blame] | 149 | 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 Cox | f7f6329 | 2008-08-05 14:21:42 -0700 | [diff] [blame] | 154 | |
Russ Cox | 3609624 | 2009-01-16 14:58:14 -0800 | [diff] [blame] | 155 | sys_Exit(2); |
Rob Pike | 7b210c5 | 2008-06-23 16:34:17 -0700 | [diff] [blame] | 156 | } |
| 157 | |
Russ Cox | dfa5893 | 2008-12-03 14:21:28 -0800 | [diff] [blame] | 158 | void |
| 159 | sigignore(int32, struct siginfo*, void*) |
| 160 | { |
| 161 | } |
| 162 | |
Russ Cox | a67258f | 2008-09-18 15:56:46 -0700 | [diff] [blame] | 163 | struct stack_t { |
| 164 | byte *sp; |
| 165 | int64 size; |
| 166 | int32 flags; |
| 167 | }; |
Robert Griesemer | 3311e1b | 2008-06-25 17:07:22 -0700 | [diff] [blame] | 168 | |
Rob Pike | aeb4398 | 2008-06-21 15:36:23 -0700 | [diff] [blame] | 169 | void |
Russ Cox | a67258f | 2008-09-18 15:56:46 -0700 | [diff] [blame] | 170 | signalstack(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 Cox | dfa5893 | 2008-12-03 14:21:28 -0800 | [diff] [blame] | 180 | void sigaction(int64, void*, void*); |
| 181 | |
| 182 | enum { |
| 183 | SA_SIGINFO = 0x40, |
| 184 | SA_RESTART = 0x02, |
| 185 | SA_ONSTACK = 0x01, |
| 186 | SA_USERTRAMP = 0x100, |
| 187 | SA_64REGSET = 0x200, |
| 188 | }; |
| 189 | |
Russ Cox | a67258f | 2008-09-18 15:56:46 -0700 | [diff] [blame] | 190 | void |
Rob Pike | aeb4398 | 2008-06-21 15:36:23 -0700 | [diff] [blame] | 191 | initsig(void) |
| 192 | { |
Rob Pike | 7b210c5 | 2008-06-23 16:34:17 -0700 | [diff] [blame] | 193 | int32 i; |
Russ Cox | dfa5893 | 2008-12-03 14:21:28 -0800 | [diff] [blame] | 194 | static struct sigaction sa; |
Russ Cox | a67258f | 2008-09-18 15:56:46 -0700 | [diff] [blame] | 195 | |
Russ Cox | dfa5893 | 2008-12-03 14:21:28 -0800 | [diff] [blame] | 196 | 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 Pike | 7b210c5 | 2008-06-23 16:34:17 -0700 | [diff] [blame] | 211 | } |
Russ Cox | dfa5893 | 2008-12-03 14:21:28 -0800 | [diff] [blame] | 212 | } |
Rob Pike | aeb4398 | 2008-06-21 15:36:23 -0700 | [diff] [blame] | 213 | } |
Russ Cox | d28acc4 | 2008-08-04 16:43:49 -0700 | [diff] [blame] | 214 | |
| 215 | static void |
| 216 | unimplemented(int8 *name) |
| 217 | { |
| 218 | prints(name); |
| 219 | prints(" not implemented\n"); |
| 220 | *(int32*)1231 = 1231; |
| 221 | } |
| 222 | |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 223 | // 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. |
| 228 | static void |
| 229 | initsema(uint32 *psema) |
| 230 | { |
| 231 | uint32 sema; |
| 232 | |
| 233 | if(*psema != 0) // already have one |
| 234 | return; |
| 235 | |
Russ Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 236 | sema = mach_semcreate(); |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 237 | if(!cas(psema, 0, sema)){ |
| 238 | // Someone else filled it in. Use theirs. |
Russ Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 239 | mach_semdestroy(sema); |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 240 | return; |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | |
| 245 | // Atomic add and return new value. |
| 246 | static uint32 |
| 247 | xadd(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 Cox | 5ff12f8 | 2008-09-24 10:25:28 -0700 | [diff] [blame] | 271 | // in Plan 9's user-level locks. |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 272 | // |
| 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 Cox | d28acc4 | 2008-08-04 16:43:49 -0700 | [diff] [blame] | 277 | void |
| 278 | lock(Lock *l) |
| 279 | { |
Russ Cox | 53e69e1 | 2009-01-27 14:01:20 -0800 | [diff] [blame] | 280 | if(m->locks < 0) |
| 281 | throw("lock count"); |
| 282 | m->locks++; |
| 283 | |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 284 | // 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 Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 289 | mach_semacquire(l->sema); |
Russ Cox | d28acc4 | 2008-08-04 16:43:49 -0700 | [diff] [blame] | 290 | } |
| 291 | |
| 292 | void |
| 293 | unlock(Lock *l) |
| 294 | { |
Russ Cox | 1ce1791 | 2009-01-26 17:37:05 -0800 | [diff] [blame] | 295 | m->locks--; |
Russ Cox | 53e69e1 | 2009-01-27 14:01:20 -0800 | [diff] [blame] | 296 | if(m->locks < 0) |
| 297 | throw("lock count"); |
| 298 | |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 299 | if(xadd(&l->key, -1) > 0) // someone else is waiting |
Russ Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 300 | mach_semrelease(l->sema); |
Russ Cox | d28acc4 | 2008-08-04 16:43:49 -0700 | [diff] [blame] | 301 | } |
| 302 | |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 303 | |
Russ Cox | 5ff12f8 | 2008-09-24 10:25:28 -0700 | [diff] [blame] | 304 | // 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. |
| 308 | void |
| 309 | usemacquire(Usema *s) |
| 310 | { |
| 311 | if((int32)xadd(&s->u, -1) < 0) |
Russ Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 312 | mach_semacquire(s->k); |
Russ Cox | 5ff12f8 | 2008-09-24 10:25:28 -0700 | [diff] [blame] | 313 | } |
| 314 | |
| 315 | void |
| 316 | usemrelease(Usema *s) |
| 317 | { |
| 318 | if((int32)xadd(&s->u, 1) <= 0) |
Russ Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 319 | mach_semrelease(s->k); |
Russ Cox | 5ff12f8 | 2008-09-24 10:25:28 -0700 | [diff] [blame] | 320 | } |
| 321 | |
| 322 | |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 323 | // Event notifications. |
Russ Cox | d28acc4 | 2008-08-04 16:43:49 -0700 | [diff] [blame] | 324 | void |
Russ Cox | 9682400 | 2008-08-05 14:18:47 -0700 | [diff] [blame] | 325 | noteclear(Note *n) |
Russ Cox | d28acc4 | 2008-08-04 16:43:49 -0700 | [diff] [blame] | 326 | { |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 327 | n->wakeup = 0; |
Russ Cox | d28acc4 | 2008-08-04 16:43:49 -0700 | [diff] [blame] | 328 | } |
| 329 | |
| 330 | void |
Russ Cox | 9682400 | 2008-08-05 14:18:47 -0700 | [diff] [blame] | 331 | notesleep(Note *n) |
Russ Cox | d28acc4 | 2008-08-04 16:43:49 -0700 | [diff] [blame] | 332 | { |
Russ Cox | 5ff12f8 | 2008-09-24 10:25:28 -0700 | [diff] [blame] | 333 | if(n->sema.k == 0) |
| 334 | initsema(&n->sema.k); |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 335 | while(!n->wakeup) |
Russ Cox | 5ff12f8 | 2008-09-24 10:25:28 -0700 | [diff] [blame] | 336 | usemacquire(&n->sema); |
Russ Cox | d28acc4 | 2008-08-04 16:43:49 -0700 | [diff] [blame] | 337 | } |
| 338 | |
| 339 | void |
Russ Cox | 9682400 | 2008-08-05 14:18:47 -0700 | [diff] [blame] | 340 | notewakeup(Note *n) |
Russ Cox | d28acc4 | 2008-08-04 16:43:49 -0700 | [diff] [blame] | 341 | { |
Russ Cox | 5ff12f8 | 2008-09-24 10:25:28 -0700 | [diff] [blame] | 342 | if(n->sema.k == 0) |
| 343 | initsema(&n->sema.k); |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 344 | n->wakeup = 1; |
Russ Cox | 5ff12f8 | 2008-09-24 10:25:28 -0700 | [diff] [blame] | 345 | usemrelease(&n->sema); |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 346 | } |
| 347 | |
| 348 | |
| 349 | // BSD interface for threading. |
| 350 | void |
| 351 | osinit(void) |
| 352 | { |
| 353 | // Register our thread-creation callback (see sys_amd64_darwin.s). |
| 354 | bsdthread_register(); |
Russ Cox | d28acc4 | 2008-08-04 16:43:49 -0700 | [diff] [blame] | 355 | } |
| 356 | |
| 357 | void |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 358 | newosproc(M *m, G *g, void *stk, void (*fn)(void)) |
Russ Cox | d28acc4 | 2008-08-04 16:43:49 -0700 | [diff] [blame] | 359 | { |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 360 | bsdthread_create(stk, m, g, fn); |
Russ Cox | d28acc4 | 2008-08-04 16:43:49 -0700 | [diff] [blame] | 361 | } |
| 362 | |
Russ Cox | a67258f | 2008-09-18 15:56:46 -0700 | [diff] [blame] | 363 | // Called to initialize a new m (including the bootstrap m). |
| 364 | void |
| 365 | minit(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 Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 372 | |
| 373 | // Mach IPC, to get at semaphores |
| 374 | // Definitions are in /usr/include/mach on a Mac. |
| 375 | |
| 376 | static void |
| 377 | macherror(kern_return_t r, int8 *fn) |
Russ Cox | d28acc4 | 2008-08-04 16:43:49 -0700 | [diff] [blame] | 378 | { |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 379 | prints("mach error "); |
| 380 | prints(fn); |
| 381 | prints(": "); |
| 382 | sys·printint(r); |
| 383 | prints("\n"); |
| 384 | throw("mach error"); |
| 385 | } |
| 386 | |
| 387 | enum |
| 388 | { |
| 389 | DebugMach = 0 |
| 390 | }; |
| 391 | |
| 392 | typedef int32 mach_msg_option_t; |
| 393 | typedef uint32 mach_msg_bits_t; |
| 394 | typedef uint32 mach_msg_id_t; |
| 395 | typedef uint32 mach_msg_size_t; |
| 396 | typedef uint32 mach_msg_timeout_t; |
| 397 | typedef uint32 mach_port_name_t; |
| 398 | typedef uint64 mach_vm_address_t; |
| 399 | |
| 400 | typedef struct mach_msg_header_t mach_msg_header_t; |
| 401 | typedef struct mach_msg_body_t mach_msg_body_t; |
| 402 | typedef struct mach_msg_port_descriptor_t mach_msg_port_descriptor_t; |
| 403 | typedef struct NDR_record_t NDR_record_t; |
| 404 | |
| 405 | enum |
| 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 | |
| 437 | mach_port_t mach_task_self(void); |
| 438 | mach_port_t mach_thread_self(void); |
| 439 | |
| 440 | #pragma pack on |
| 441 | struct 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 | |
| 451 | struct mach_msg_body_t |
| 452 | { |
| 453 | uint32 descriptor_count; |
| 454 | }; |
| 455 | |
| 456 | struct 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 | |
| 465 | enum |
| 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 | |
| 474 | struct 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 | |
| 487 | static 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) |
| 492 | kern_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); |
| 495 | mach_port_t mach_reply_port(void); |
| 496 | mach_port_t mach_task_self(void); |
| 497 | mach_port_t mach_thread_self(void); |
| 498 | |
| 499 | static kern_return_t |
| 500 | mach_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 | |
| 516 | enum |
| 517 | { |
| 518 | MinMachMsg = 48, |
| 519 | Reply = 100, |
| 520 | }; |
| 521 | |
| 522 | #pragma pack on |
| 523 | typedef struct CodeMsg CodeMsg; |
| 524 | struct CodeMsg |
| 525 | { |
| 526 | mach_msg_header_t h; |
| 527 | NDR_record_t NDR; |
| 528 | kern_return_t code; |
| 529 | }; |
| 530 | #pragma pack off |
| 531 | |
| 532 | static kern_return_t |
| 533 | machcall(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 Cox | d28acc4 | 2008-08-04 16:43:49 -0700 | [diff] [blame] | 626 | return 0; |
| 627 | } |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 628 | |
| 629 | |
| 630 | // Semaphores! |
| 631 | |
| 632 | enum |
| 633 | { |
Russ Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 634 | Tmach_semcreate = 3418, |
| 635 | Rmach_semcreate = Tmach_semcreate + Reply, |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 636 | |
Russ Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 637 | Tmach_semdestroy = 3419, |
| 638 | Rmach_semdestroy = Tmach_semdestroy + Reply, |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 639 | }; |
| 640 | |
Russ Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 641 | typedef struct Tmach_semcreateMsg Tmach_semcreateMsg; |
| 642 | typedef struct Rmach_semcreateMsg Rmach_semcreateMsg; |
| 643 | typedef struct Tmach_semdestroyMsg Tmach_semdestroyMsg; |
| 644 | // Rmach_semdestroyMsg = CodeMsg |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 645 | |
| 646 | #pragma pack on |
Russ Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 647 | struct Tmach_semcreateMsg |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 648 | { |
| 649 | mach_msg_header_t h; |
| 650 | NDR_record_t ndr; |
| 651 | int32 policy; |
| 652 | int32 value; |
| 653 | }; |
| 654 | |
Russ Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 655 | struct Rmach_semcreateMsg |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 656 | { |
| 657 | mach_msg_header_t h; |
| 658 | mach_msg_body_t body; |
| 659 | mach_msg_port_descriptor_t semaphore; |
| 660 | }; |
| 661 | |
Russ Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 662 | struct Tmach_semdestroyMsg |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 663 | { |
| 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 | |
| 670 | mach_port_t |
Russ Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 671 | mach_semcreate(void) |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 672 | { |
| 673 | union { |
Russ Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 674 | Tmach_semcreateMsg tx; |
| 675 | Rmach_semcreateMsg rx; |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 676 | 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 Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 683 | m.tx.h.id = Tmach_semcreate; |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 684 | 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 Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 692 | unimplemented("mach_semcreate desc count"); |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 693 | return m.rx.semaphore.name; |
| 694 | } |
| 695 | |
| 696 | void |
Russ Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 697 | mach_semdestroy(mach_port_t sem) |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 698 | { |
| 699 | union { |
Russ Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 700 | Tmach_semdestroyMsg tx; |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 701 | 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 Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 708 | m.tx.h.id = Tmach_semdestroy; |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 709 | 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 |
| 720 | kern_return_t mach_semaphore_wait(uint32 sema); |
| 721 | kern_return_t mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec); |
| 722 | kern_return_t mach_semaphore_signal(uint32 sema); |
| 723 | kern_return_t mach_semaphore_signal_all(uint32 sema); |
| 724 | |
| 725 | void |
Russ Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 726 | mach_semacquire(mach_port_t sem) |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 727 | { |
| 728 | kern_return_t r; |
| 729 | |
| 730 | if((r = mach_semaphore_wait(sem)) != 0) |
| 731 | macherror(r, "semaphore_wait"); |
| 732 | } |
| 733 | |
| 734 | void |
Russ Cox | 1f8a40d | 2009-01-22 16:23:44 -0800 | [diff] [blame] | 735 | mach_semrelease(mach_port_t sem) |
Russ Cox | 376898c | 2008-09-09 11:50:14 -0700 | [diff] [blame] | 736 | { |
| 737 | kern_return_t r; |
| 738 | |
| 739 | if((r = mach_semaphore_signal(sem)) != 0) |
| 740 | macherror(r, "semaphore_signal"); |
| 741 | } |
| 742 | |