diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-09-13 13:13:40 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-09-13 13:13:40 +0200 |
commit | 5ff4c17907d5b19510a62e08fd8d3b11e62b431d (patch) | |
tree | c0650497e988f47be9c6f2324fa692a52dea82e1 /src/pkg/runtime/darwin | |
parent | 80f18fc933cf3f3e829c5455a1023d69f7b86e52 (diff) | |
download | golang-upstream/60.tar.gz |
Imported Upstream version 60upstream/60
Diffstat (limited to 'src/pkg/runtime/darwin')
-rw-r--r-- | src/pkg/runtime/darwin/386/defs.h | 289 | ||||
-rw-r--r-- | src/pkg/runtime/darwin/386/rt0.s | 8 | ||||
-rw-r--r-- | src/pkg/runtime/darwin/386/signal.c | 194 | ||||
-rw-r--r-- | src/pkg/runtime/darwin/386/sys.s | 311 | ||||
-rw-r--r-- | src/pkg/runtime/darwin/amd64/defs.h | 305 | ||||
-rw-r--r-- | src/pkg/runtime/darwin/amd64/rt0.s | 10 | ||||
-rw-r--r-- | src/pkg/runtime/darwin/amd64/signal.c | 204 | ||||
-rw-r--r-- | src/pkg/runtime/darwin/amd64/sys.s | 295 | ||||
-rw-r--r-- | src/pkg/runtime/darwin/defs.c | 159 | ||||
-rw-r--r-- | src/pkg/runtime/darwin/mem.c | 55 | ||||
-rw-r--r-- | src/pkg/runtime/darwin/os.h | 31 | ||||
-rw-r--r-- | src/pkg/runtime/darwin/signals.h | 51 | ||||
-rw-r--r-- | src/pkg/runtime/darwin/thread.c | 484 |
13 files changed, 2396 insertions, 0 deletions
diff --git a/src/pkg/runtime/darwin/386/defs.h b/src/pkg/runtime/darwin/386/defs.h new file mode 100644 index 000000000..bb70207fd --- /dev/null +++ b/src/pkg/runtime/darwin/386/defs.h @@ -0,0 +1,289 @@ +// godefs -f -m32 defs.c + +// MACHINE GENERATED - DO NOT EDIT. + +// Constants +enum { + PROT_NONE = 0, + PROT_READ = 0x1, + PROT_WRITE = 0x2, + PROT_EXEC = 0x4, + MAP_ANON = 0x1000, + MAP_PRIVATE = 0x2, + MAP_FIXED = 0x10, + MACH_MSG_TYPE_MOVE_RECEIVE = 0x10, + MACH_MSG_TYPE_MOVE_SEND = 0x11, + MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12, + MACH_MSG_TYPE_COPY_SEND = 0x13, + MACH_MSG_TYPE_MAKE_SEND = 0x14, + MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15, + MACH_MSG_TYPE_COPY_RECEIVE = 0x16, + MACH_MSG_PORT_DESCRIPTOR = 0, + MACH_MSG_OOL_DESCRIPTOR = 0x1, + MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2, + MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3, + MACH_MSGH_BITS_COMPLEX = 0x80000000, + MACH_SEND_MSG = 0x1, + MACH_RCV_MSG = 0x2, + MACH_RCV_LARGE = 0x4, + MACH_SEND_TIMEOUT = 0x10, + MACH_SEND_INTERRUPT = 0x40, + MACH_SEND_CANCEL = 0x80, + MACH_SEND_ALWAYS = 0x10000, + MACH_SEND_TRAILER = 0x20000, + MACH_RCV_TIMEOUT = 0x100, + MACH_RCV_NOTIFY = 0x200, + MACH_RCV_INTERRUPT = 0x400, + MACH_RCV_OVERWRITE = 0x1000, + NDR_PROTOCOL_2_0 = 0, + NDR_INT_BIG_ENDIAN = 0, + NDR_INT_LITTLE_ENDIAN = 0x1, + NDR_FLOAT_IEEE = 0, + NDR_CHAR_ASCII = 0, + SA_SIGINFO = 0x40, + SA_RESTART = 0x2, + SA_ONSTACK = 0x1, + SA_USERTRAMP = 0x100, + SA_64REGSET = 0x200, + SIGHUP = 0x1, + SIGINT = 0x2, + SIGQUIT = 0x3, + SIGILL = 0x4, + SIGTRAP = 0x5, + SIGABRT = 0x6, + SIGEMT = 0x7, + SIGFPE = 0x8, + SIGKILL = 0x9, + SIGBUS = 0xa, + SIGSEGV = 0xb, + SIGSYS = 0xc, + SIGPIPE = 0xd, + SIGALRM = 0xe, + SIGTERM = 0xf, + SIGURG = 0x10, + SIGSTOP = 0x11, + SIGTSTP = 0x12, + SIGCONT = 0x13, + SIGCHLD = 0x14, + SIGTTIN = 0x15, + SIGTTOU = 0x16, + SIGIO = 0x17, + SIGXCPU = 0x18, + SIGXFSZ = 0x19, + SIGVTALRM = 0x1a, + SIGPROF = 0x1b, + SIGWINCH = 0x1c, + SIGINFO = 0x1d, + SIGUSR1 = 0x1e, + SIGUSR2 = 0x1f, + FPE_INTDIV = 0x7, + FPE_INTOVF = 0x8, + FPE_FLTDIV = 0x1, + FPE_FLTOVF = 0x2, + FPE_FLTUND = 0x3, + FPE_FLTRES = 0x4, + FPE_FLTINV = 0x5, + FPE_FLTSUB = 0x6, + BUS_ADRALN = 0x1, + BUS_ADRERR = 0x2, + BUS_OBJERR = 0x3, + SEGV_MAPERR = 0x1, + SEGV_ACCERR = 0x2, + ITIMER_REAL = 0, + ITIMER_VIRTUAL = 0x1, + ITIMER_PROF = 0x2, +}; + +// Types +#pragma pack on + +typedef struct MachBody MachBody; +struct MachBody { + uint32 msgh_descriptor_count; +}; + +typedef struct MachHeader MachHeader; +struct MachHeader { + uint32 msgh_bits; + uint32 msgh_size; + uint32 msgh_remote_port; + uint32 msgh_local_port; + uint32 msgh_reserved; + int32 msgh_id; +}; + +typedef struct MachNDR MachNDR; +struct MachNDR { + uint8 mig_vers; + uint8 if_vers; + uint8 reserved1; + uint8 mig_encoding; + uint8 int_rep; + uint8 char_rep; + uint8 float_rep; + uint8 reserved2; +}; + +typedef struct MachPort MachPort; +struct MachPort { + uint32 name; + uint32 pad1; + uint16 pad2; + uint8 disposition; + uint8 type; +}; + +typedef struct StackT StackT; +struct StackT { + void *ss_sp; + uint32 ss_size; + int32 ss_flags; +}; + +typedef union Sighandler Sighandler; +union Sighandler { + uint32 __sa_handler; + uint32 __sa_sigaction; +}; + +typedef struct Sigaction Sigaction; +struct Sigaction { + Sighandler __sigaction_u; + uint32 sa_tramp; + uint32 sa_mask; + int32 sa_flags; +}; + +typedef union Sigval Sigval; +union Sigval { + int32 sival_int; + void *sival_ptr; +}; + +typedef struct Siginfo Siginfo; +struct Siginfo { + int32 si_signo; + int32 si_errno; + int32 si_code; + int32 si_pid; + uint32 si_uid; + int32 si_status; + void *si_addr; + Sigval si_value; + int32 si_band; + uint32 __pad[7]; +}; + +typedef struct Timeval Timeval; +struct Timeval { + int32 tv_sec; + int32 tv_usec; +}; + +typedef struct Itimerval Itimerval; +struct Itimerval { + Timeval it_interval; + Timeval it_value; +}; + +typedef struct FPControl FPControl; +struct FPControl { + byte pad_godefs_0[2]; +}; + +typedef struct FPStatus FPStatus; +struct FPStatus { + byte pad_godefs_0[2]; +}; + +typedef struct RegMMST RegMMST; +struct RegMMST { + int8 mmst_reg[10]; + int8 mmst_rsrv[6]; +}; + +typedef struct RegXMM RegXMM; +struct RegXMM { + int8 xmm_reg[16]; +}; + +typedef struct Regs Regs; +struct Regs { + uint32 eax; + uint32 ebx; + uint32 ecx; + uint32 edx; + uint32 edi; + uint32 esi; + uint32 ebp; + uint32 esp; + uint32 ss; + uint32 eflags; + uint32 eip; + uint32 cs; + uint32 ds; + uint32 es; + uint32 fs; + uint32 gs; +}; + +typedef struct FloatState FloatState; +struct FloatState { + uint64 fpu_reserved; + FPControl fpu_fcw; + FPStatus fpu_fsw; + uint8 fpu_ftw; + uint8 fpu_rsrv1; + uint16 fpu_fop; + uint32 fpu_ip; + uint16 fpu_cs; + uint16 fpu_rsrv2; + uint32 fpu_dp; + uint16 fpu_ds; + uint16 fpu_rsrv3; + uint32 fpu_mxcsr; + uint32 fpu_mxcsrmask; + RegMMST fpu_stmm0; + RegMMST fpu_stmm1; + RegMMST fpu_stmm2; + RegMMST fpu_stmm3; + RegMMST fpu_stmm4; + RegMMST fpu_stmm5; + RegMMST fpu_stmm6; + RegMMST fpu_stmm7; + RegXMM fpu_xmm0; + RegXMM fpu_xmm1; + RegXMM fpu_xmm2; + RegXMM fpu_xmm3; + RegXMM fpu_xmm4; + RegXMM fpu_xmm5; + RegXMM fpu_xmm6; + RegXMM fpu_xmm7; + int8 fpu_rsrv4[224]; + int32 fpu_reserved1; +}; + +typedef struct ExceptionState ExceptionState; +struct ExceptionState { + uint32 trapno; + uint32 err; + uint32 faultvaddr; +}; + +typedef struct Mcontext Mcontext; +struct Mcontext { + ExceptionState es; + Regs ss; + FloatState fs; +}; + +typedef struct Ucontext Ucontext; +struct Ucontext { + int32 uc_onstack; + uint32 uc_sigmask; + StackT uc_stack; + uint32 uc_link; + uint32 uc_mcsize; + Mcontext *uc_mcontext; +}; +#pragma pack off diff --git a/src/pkg/runtime/darwin/386/rt0.s b/src/pkg/runtime/darwin/386/rt0.s new file mode 100644 index 000000000..30b497f5e --- /dev/null +++ b/src/pkg/runtime/darwin/386/rt0.s @@ -0,0 +1,8 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Darwin and Linux use the same linkage to main + +TEXT _rt0_386_darwin(SB),7,$0 + JMP _rt0_386(SB) diff --git a/src/pkg/runtime/darwin/386/signal.c b/src/pkg/runtime/darwin/386/signal.c new file mode 100644 index 000000000..29170b669 --- /dev/null +++ b/src/pkg/runtime/darwin/386/signal.c @@ -0,0 +1,194 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "runtime.h" +#include "defs.h" +#include "os.h" +#include "signals.h" + +void +runtime·dumpregs(Regs *r) +{ + runtime·printf("eax %x\n", r->eax); + runtime·printf("ebx %x\n", r->ebx); + runtime·printf("ecx %x\n", r->ecx); + runtime·printf("edx %x\n", r->edx); + runtime·printf("edi %x\n", r->edi); + runtime·printf("esi %x\n", r->esi); + runtime·printf("ebp %x\n", r->ebp); + runtime·printf("esp %x\n", r->esp); + runtime·printf("eip %x\n", r->eip); + runtime·printf("eflags %x\n", r->eflags); + runtime·printf("cs %x\n", r->cs); + runtime·printf("fs %x\n", r->fs); + runtime·printf("gs %x\n", r->gs); +} + +String +runtime·signame(int32 sig) +{ + if(sig < 0 || sig >= NSIG) + return runtime·emptystring; + return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name); +} + +void +runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) +{ + Ucontext *uc; + Mcontext *mc; + Regs *r; + uintptr *sp; + byte *pc; + + uc = context; + mc = uc->uc_mcontext; + r = &mc->ss; + + if(sig == SIGPROF) { + runtime·sigprof((uint8*)r->eip, (uint8*)r->esp, nil, gp); + return; + } + + if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) { + // Work around Leopard bug that doesn't set FPE_INTDIV. + // Look at instruction to see if it is a divide. + // Not necessary in Snow Leopard (si_code will be != 0). + if(sig == SIGFPE && info->si_code == 0) { + pc = (byte*)r->eip; + if(pc[0] == 0x66) // 16-bit instruction prefix + pc++; + if(pc[0] == 0xF6 || pc[0] == 0xF7) + info->si_code = FPE_INTDIV; + } + + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp->sig = sig; + gp->sigcode0 = info->si_code; + gp->sigcode1 = (uintptr)info->si_addr; + gp->sigpc = r->eip; + + // Only push runtime·sigpanic if r->eip != 0. + // If r->eip == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime·sigpanic instead. + // (Otherwise the trace will end at runtime·sigpanic and we + // won't get to see who faulted.) + if(r->eip != 0) { + sp = (uintptr*)r->esp; + *--sp = r->eip; + r->esp = (uintptr)sp; + } + r->eip = (uintptr)runtime·sigpanic; + return; + } + + if(runtime·sigtab[sig].flags & SigQueue) { + if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore)) + return; + runtime·exit(2); // SIGINT, SIGTERM, etc + } + + if(runtime·panicking) // traceback already printed + runtime·exit(2); + runtime·panicking = 1; + + if(sig < 0 || sig >= NSIG){ + runtime·printf("Signal %d\n", sig); + }else{ + runtime·printf("%s\n", runtime·sigtab[sig].name); + } + + runtime·printf("pc: %x\n", r->eip); + runtime·printf("\n"); + + if(runtime·gotraceback()){ + runtime·traceback((void*)r->eip, (void*)r->esp, 0, gp); + runtime·tracebackothers(gp); + runtime·dumpregs(r); + } + + runtime·exit(2); +} + +void +runtime·sigignore(int32, Siginfo*, void*) +{ +} + +void +runtime·signalstack(byte *p, int32 n) +{ + StackT st; + + st.ss_sp = p; + st.ss_size = n; + st.ss_flags = 0; + runtime·sigaltstack(&st, nil); +} + +static void +sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) +{ + Sigaction sa; + + runtime·memclr((byte*)&sa, sizeof sa); + sa.sa_flags = SA_SIGINFO|SA_ONSTACK; + if(restart) + sa.sa_flags |= SA_RESTART; + sa.sa_mask = ~0U; + sa.sa_tramp = (uintptr)runtime·sigtramp; // runtime·sigtramp's job is to call into real handler + sa.__sigaction_u.__sa_sigaction = (uintptr)fn; + runtime·sigaction(i, &sa, nil); +} + +void +runtime·initsig(int32 queue) +{ + int32 i; + void *fn; + + runtime·siginit(); + + for(i = 0; i<NSIG; i++) { + if(runtime·sigtab[i].flags) { + if((runtime·sigtab[i].flags & SigQueue) != queue) + continue; + if(runtime·sigtab[i].flags & (SigCatch | SigQueue)) + fn = runtime·sighandler; + else + fn = runtime·sigignore; + sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0); + } + } +} + +void +runtime·resetcpuprofiler(int32 hz) +{ + Itimerval it; + + runtime·memclr((byte*)&it, sizeof it); + if(hz == 0) { + runtime·setitimer(ITIMER_PROF, &it, nil); + sigaction(SIGPROF, SIG_IGN, true); + } else { + sigaction(SIGPROF, runtime·sighandler, true); + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 1000000 / hz; + it.it_value = it.it_interval; + runtime·setitimer(ITIMER_PROF, &it, nil); + } + m->profilehz = hz; +} + +void +os·sigpipe(void) +{ + sigaction(SIGPIPE, SIG_DFL, false); + runtime·raisesigpipe(); +} diff --git a/src/pkg/runtime/darwin/386/sys.s b/src/pkg/runtime/darwin/386/sys.s new file mode 100644 index 000000000..87fbdbb79 --- /dev/null +++ b/src/pkg/runtime/darwin/386/sys.s @@ -0,0 +1,311 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// System calls and other sys.stuff for 386, Darwin +// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228 +// or /usr/include/sys/syscall.h (on a Mac) for system call numbers. + +#include "386/asm.h" + +TEXT runtime·notok(SB),7,$0 + MOVL $0xf1, 0xf1 + RET + +// Exit the entire program (like C exit) +TEXT runtime·exit(SB),7,$0 + MOVL $1, AX + INT $0x80 + CALL runtime·notok(SB) + RET + +// Exit this OS thread (like pthread_exit, which eventually +// calls __bsdthread_terminate). +TEXT runtime·exit1(SB),7,$0 + MOVL $361, AX + INT $0x80 + JAE 2(PC) + CALL runtime·notok(SB) + RET + +TEXT runtime·write(SB),7,$0 + MOVL $4, AX + INT $0x80 + RET + +TEXT runtime·raisesigpipe(SB),7,$8 + get_tls(CX) + MOVL m(CX), DX + MOVL m_procid(DX), DX + MOVL DX, 0(SP) // thread_port + MOVL $13, 4(SP) // signal: SIGPIPE + MOVL $328, AX // __pthread_kill + INT $0x80 + RET + +TEXT runtime·mmap(SB),7,$0 + MOVL $197, AX + INT $0x80 + RET + +TEXT runtime·munmap(SB),7,$0 + MOVL $73, AX + INT $0x80 + JAE 2(PC) + CALL runtime·notok(SB) + RET + +TEXT runtime·setitimer(SB),7,$0 + MOVL $83, AX + INT $0x80 + RET + +// void gettime(int64 *sec, int32 *usec) +TEXT runtime·gettime(SB), 7, $32 + LEAL 12(SP), AX // must be non-nil, unused + MOVL AX, 4(SP) + MOVL $0, 8(SP) // time zone pointer + MOVL $116, AX + INT $0x80 + + MOVL sec+0(FP), DI + MOVL AX, (DI) + MOVL $0, 4(DI) // zero extend 32 -> 64 + + MOVL usec+4(FP), DI + MOVL DX, (DI) + RET + +TEXT runtime·sigaction(SB),7,$0 + MOVL $46, AX + INT $0x80 + JAE 2(PC) + CALL runtime·notok(SB) + RET + +// Sigtramp's job is to call the actual signal handler. +// It is called with the following arguments on the stack: +// 0(FP) "return address" - ignored +// 4(FP) actual handler +// 8(FP) siginfo style - ignored +// 12(FP) signal number +// 16(FP) siginfo +// 20(FP) context +TEXT runtime·sigtramp(SB),7,$40 + get_tls(CX) + + // save g + MOVL g(CX), DI + MOVL DI, 20(SP) + + // g = m->gsignal + MOVL m(CX), BP + MOVL m_gsignal(BP), BP + MOVL BP, g(CX) + + // copy arguments to sighandler + MOVL sig+8(FP), BX + MOVL BX, 0(SP) + MOVL info+12(FP), BX + MOVL BX, 4(SP) + MOVL context+16(FP), BX + MOVL BX, 8(SP) + MOVL DI, 12(SP) + + MOVL handler+0(FP), BX + CALL BX + + // restore g + get_tls(CX) + MOVL 20(SP), DI + MOVL DI, g(CX) + + // call sigreturn + MOVL context+16(FP), CX + MOVL style+4(FP), BX + MOVL $0, 0(SP) // "caller PC" - ignored + MOVL CX, 4(SP) + MOVL BX, 8(SP) + MOVL $184, AX // sigreturn(ucontext, infostyle) + INT $0x80 + CALL runtime·notok(SB) + RET + +TEXT runtime·sigaltstack(SB),7,$0 + MOVL $53, AX + INT $0x80 + JAE 2(PC) + CALL runtime·notok(SB) + RET + +// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void)) +// System call args are: func arg stack pthread flags. +TEXT runtime·bsdthread_create(SB),7,$32 + MOVL $360, AX + // 0(SP) is where the caller PC would be; kernel skips it + MOVL func+12(FP), BX + MOVL BX, 4(SP) // func + MOVL mm+4(FP), BX + MOVL BX, 8(SP) // arg + MOVL stk+0(FP), BX + MOVL BX, 12(SP) // stack + MOVL gg+8(FP), BX + MOVL BX, 16(SP) // pthread + MOVL $0x1000000, 20(SP) // flags = PTHREAD_START_CUSTOM + INT $0x80 + JAE 3(PC) + NEGL AX + RET + MOVL $0, AX + RET + +// The thread that bsdthread_create creates starts executing here, +// because we registered this function using bsdthread_register +// at startup. +// AX = "pthread" (= g) +// BX = mach thread port +// CX = "func" (= fn) +// DX = "arg" (= m) +// DI = stack top +// SI = flags (= 0x1000000) +// SP = stack - C_32_STK_ALIGN +TEXT runtime·bsdthread_start(SB),7,$0 + // set up ldt 7+id to point at m->tls. + // m->tls is at m+40. newosproc left + // the m->id in tls[0]. + LEAL m_tls(DX), BP + MOVL 0(BP), DI + ADDL $7, DI // m0 is LDT#7. count up. + // setldt(tls#, &tls, sizeof tls) + PUSHAL // save registers + PUSHL $32 // sizeof tls + PUSHL BP // &tls + PUSHL DI // tls # + CALL runtime·setldt(SB) + POPL AX + POPL AX + POPL AX + POPAL + + // Now segment is established. Initialize m, g. + get_tls(BP) + MOVL AX, g(BP) + MOVL DX, m(BP) + MOVL BX, m_procid(DX) // m->procid = thread port (for debuggers) + CALL runtime·stackcheck(SB) // smashes AX + CALL CX // fn() + CALL runtime·exit1(SB) + RET + +// void bsdthread_register(void) +// registers callbacks for threadstart (see bsdthread_create above +// and wqthread and pthsize (not used). returns 0 on success. +TEXT runtime·bsdthread_register(SB),7,$40 + MOVL $366, AX + // 0(SP) is where kernel expects caller PC; ignored + MOVL $runtime·bsdthread_start(SB), 4(SP) // threadstart + MOVL $0, 8(SP) // wqthread, not used by us + MOVL $0, 12(SP) // pthsize, not used by us + MOVL $0, 16(SP) // dummy_value [sic] + MOVL $0, 20(SP) // targetconc_ptr + MOVL $0, 24(SP) // dispatchqueue_offset + INT $0x80 + JAE 2(PC) + CALL runtime·notok(SB) + RET + +// Invoke Mach system call. +// Assumes system call number in AX, +// caller PC on stack, caller's caller PC next, +// and then the system call arguments. +// +// Can be used for BSD too, but we don't, +// because if you use this interface the BSD +// system call numbers need an extra field +// in the high 16 bits that seems to be the +// argument count in bytes but is not always. +// INT $0x80 works fine for those. +TEXT runtime·sysenter(SB),7,$0 + POPL DX + MOVL SP, CX + BYTE $0x0F; BYTE $0x34; // SYSENTER + // returns to DX with SP set to CX + +TEXT runtime·mach_msg_trap(SB),7,$0 + MOVL $-31, AX + CALL runtime·sysenter(SB) + RET + +TEXT runtime·mach_reply_port(SB),7,$0 + MOVL $-26, AX + CALL runtime·sysenter(SB) + RET + +TEXT runtime·mach_task_self(SB),7,$0 + MOVL $-28, AX + CALL runtime·sysenter(SB) + RET + +// Mach provides trap versions of the semaphore ops, +// instead of requiring the use of RPC. + +// uint32 mach_semaphore_wait(uint32) +TEXT runtime·mach_semaphore_wait(SB),7,$0 + MOVL $-36, AX + CALL runtime·sysenter(SB) + RET + +// uint32 mach_semaphore_timedwait(uint32, uint32, uint32) +TEXT runtime·mach_semaphore_timedwait(SB),7,$0 + MOVL $-38, AX + CALL runtime·sysenter(SB) + RET + +// uint32 mach_semaphore_signal(uint32) +TEXT runtime·mach_semaphore_signal(SB),7,$0 + MOVL $-33, AX + CALL runtime·sysenter(SB) + RET + +// uint32 mach_semaphore_signal_all(uint32) +TEXT runtime·mach_semaphore_signal_all(SB),7,$0 + MOVL $-34, AX + CALL runtime·sysenter(SB) + RET + +// setldt(int entry, int address, int limit) +// entry and limit are ignored. +TEXT runtime·setldt(SB),7,$32 + MOVL address+4(FP), BX // aka base + + /* + * When linking against the system libraries, + * we use its pthread_create and let it set up %gs + * for us. When we do that, the private storage + * we get is not at 0(GS) but at 0x468(GS). + * To insulate the rest of the tool chain from this ugliness, + * 8l rewrites 0(GS) into 0x468(GS) for us. + * To accommodate that rewrite, we translate the + * address and limit here so that 0x468(GS) maps to 0(address). + * + * See ../../../../libcgo/darwin_386.c for the derivation + * of the constant. + */ + SUBL $0x468, BX + + /* + * Must set up as USER_CTHREAD segment because + * Darwin forces that value into %gs for signal handlers, + * and if we don't set one up, we'll get a recursive + * fault trying to get into the signal handler. + * Since we have to set one up anyway, it might as + * well be the value we want. So don't bother with + * i386_set_ldt. + */ + MOVL BX, 4(SP) + MOVL $3, AX // thread_fast_set_cthread_self - machdep call #3 + INT $0x82 // sic: 0x82, not 0x80, for machdep call + + XORL AX, AX + MOVW GS, AX + RET diff --git a/src/pkg/runtime/darwin/amd64/defs.h b/src/pkg/runtime/darwin/amd64/defs.h new file mode 100644 index 000000000..90f798e8a --- /dev/null +++ b/src/pkg/runtime/darwin/amd64/defs.h @@ -0,0 +1,305 @@ +// godefs -f -m64 defs.c + +// MACHINE GENERATED - DO NOT EDIT. + +// Constants +enum { + PROT_NONE = 0, + PROT_READ = 0x1, + PROT_WRITE = 0x2, + PROT_EXEC = 0x4, + MAP_ANON = 0x1000, + MAP_PRIVATE = 0x2, + MAP_FIXED = 0x10, + MACH_MSG_TYPE_MOVE_RECEIVE = 0x10, + MACH_MSG_TYPE_MOVE_SEND = 0x11, + MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12, + MACH_MSG_TYPE_COPY_SEND = 0x13, + MACH_MSG_TYPE_MAKE_SEND = 0x14, + MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15, + MACH_MSG_TYPE_COPY_RECEIVE = 0x16, + MACH_MSG_PORT_DESCRIPTOR = 0, + MACH_MSG_OOL_DESCRIPTOR = 0x1, + MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2, + MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3, + MACH_MSGH_BITS_COMPLEX = 0x80000000, + MACH_SEND_MSG = 0x1, + MACH_RCV_MSG = 0x2, + MACH_RCV_LARGE = 0x4, + MACH_SEND_TIMEOUT = 0x10, + MACH_SEND_INTERRUPT = 0x40, + MACH_SEND_CANCEL = 0x80, + MACH_SEND_ALWAYS = 0x10000, + MACH_SEND_TRAILER = 0x20000, + MACH_RCV_TIMEOUT = 0x100, + MACH_RCV_NOTIFY = 0x200, + MACH_RCV_INTERRUPT = 0x400, + MACH_RCV_OVERWRITE = 0x1000, + NDR_PROTOCOL_2_0 = 0, + NDR_INT_BIG_ENDIAN = 0, + NDR_INT_LITTLE_ENDIAN = 0x1, + NDR_FLOAT_IEEE = 0, + NDR_CHAR_ASCII = 0, + SA_SIGINFO = 0x40, + SA_RESTART = 0x2, + SA_ONSTACK = 0x1, + SA_USERTRAMP = 0x100, + SA_64REGSET = 0x200, + SIGHUP = 0x1, + SIGINT = 0x2, + SIGQUIT = 0x3, + SIGILL = 0x4, + SIGTRAP = 0x5, + SIGABRT = 0x6, + SIGEMT = 0x7, + SIGFPE = 0x8, + SIGKILL = 0x9, + SIGBUS = 0xa, + SIGSEGV = 0xb, + SIGSYS = 0xc, + SIGPIPE = 0xd, + SIGALRM = 0xe, + SIGTERM = 0xf, + SIGURG = 0x10, + SIGSTOP = 0x11, + SIGTSTP = 0x12, + SIGCONT = 0x13, + SIGCHLD = 0x14, + SIGTTIN = 0x15, + SIGTTOU = 0x16, + SIGIO = 0x17, + SIGXCPU = 0x18, + SIGXFSZ = 0x19, + SIGVTALRM = 0x1a, + SIGPROF = 0x1b, + SIGWINCH = 0x1c, + SIGINFO = 0x1d, + SIGUSR1 = 0x1e, + SIGUSR2 = 0x1f, + FPE_INTDIV = 0x7, + FPE_INTOVF = 0x8, + FPE_FLTDIV = 0x1, + FPE_FLTOVF = 0x2, + FPE_FLTUND = 0x3, + FPE_FLTRES = 0x4, + FPE_FLTINV = 0x5, + FPE_FLTSUB = 0x6, + BUS_ADRALN = 0x1, + BUS_ADRERR = 0x2, + BUS_OBJERR = 0x3, + SEGV_MAPERR = 0x1, + SEGV_ACCERR = 0x2, + ITIMER_REAL = 0, + ITIMER_VIRTUAL = 0x1, + ITIMER_PROF = 0x2, +}; + +// Types +#pragma pack on + +typedef struct MachBody MachBody; +struct MachBody { + uint32 msgh_descriptor_count; +}; + +typedef struct MachHeader MachHeader; +struct MachHeader { + uint32 msgh_bits; + uint32 msgh_size; + uint32 msgh_remote_port; + uint32 msgh_local_port; + uint32 msgh_reserved; + int32 msgh_id; +}; + +typedef struct MachNDR MachNDR; +struct MachNDR { + uint8 mig_vers; + uint8 if_vers; + uint8 reserved1; + uint8 mig_encoding; + uint8 int_rep; + uint8 char_rep; + uint8 float_rep; + uint8 reserved2; +}; + +typedef struct MachPort MachPort; +struct MachPort { + uint32 name; + uint32 pad1; + uint16 pad2; + uint8 disposition; + uint8 type; +}; + +typedef struct StackT StackT; +struct StackT { + void *ss_sp; + uint64 ss_size; + int32 ss_flags; + byte pad_godefs_0[4]; +}; + +typedef union Sighandler Sighandler; +union Sighandler { + uint64 __sa_handler; + uint64 __sa_sigaction; +}; + +typedef struct Sigaction Sigaction; +struct Sigaction { + Sighandler __sigaction_u; + uint64 sa_tramp; + uint32 sa_mask; + int32 sa_flags; +}; + +typedef union Sigval Sigval; +union Sigval { + int32 sival_int; + void *sival_ptr; +}; + +typedef struct Siginfo Siginfo; +struct Siginfo { + int32 si_signo; + int32 si_errno; + int32 si_code; + int32 si_pid; + uint32 si_uid; + int32 si_status; + void *si_addr; + Sigval si_value; + int64 si_band; + uint64 __pad[7]; +}; + +typedef struct Timeval Timeval; +struct Timeval { + int64 tv_sec; + int32 tv_usec; + byte pad_godefs_0[4]; +}; + +typedef struct Itimerval Itimerval; +struct Itimerval { + Timeval it_interval; + Timeval it_value; +}; + +typedef struct FPControl FPControl; +struct FPControl { + byte pad_godefs_0[2]; +}; + +typedef struct FPStatus FPStatus; +struct FPStatus { + byte pad_godefs_0[2]; +}; + +typedef struct RegMMST RegMMST; +struct RegMMST { + int8 mmst_reg[10]; + int8 mmst_rsrv[6]; +}; + +typedef struct RegXMM RegXMM; +struct RegXMM { + int8 xmm_reg[16]; +}; + +typedef struct Regs Regs; +struct Regs { + uint64 rax; + uint64 rbx; + uint64 rcx; + uint64 rdx; + uint64 rdi; + uint64 rsi; + uint64 rbp; + uint64 rsp; + uint64 r8; + uint64 r9; + uint64 r10; + uint64 r11; + uint64 r12; + uint64 r13; + uint64 r14; + uint64 r15; + uint64 rip; + uint64 rflags; + uint64 cs; + uint64 fs; + uint64 gs; +}; + +typedef struct FloatState FloatState; +struct FloatState { + uint64 fpu_reserved; + FPControl fpu_fcw; + FPStatus fpu_fsw; + uint8 fpu_ftw; + uint8 fpu_rsrv1; + uint16 fpu_fop; + uint32 fpu_ip; + uint16 fpu_cs; + uint16 fpu_rsrv2; + uint32 fpu_dp; + uint16 fpu_ds; + uint16 fpu_rsrv3; + uint32 fpu_mxcsr; + uint32 fpu_mxcsrmask; + RegMMST fpu_stmm0; + RegMMST fpu_stmm1; + RegMMST fpu_stmm2; + RegMMST fpu_stmm3; + RegMMST fpu_stmm4; + RegMMST fpu_stmm5; + RegMMST fpu_stmm6; + RegMMST fpu_stmm7; + RegXMM fpu_xmm0; + RegXMM fpu_xmm1; + RegXMM fpu_xmm2; + RegXMM fpu_xmm3; + RegXMM fpu_xmm4; + RegXMM fpu_xmm5; + RegXMM fpu_xmm6; + RegXMM fpu_xmm7; + RegXMM fpu_xmm8; + RegXMM fpu_xmm9; + RegXMM fpu_xmm10; + RegXMM fpu_xmm11; + RegXMM fpu_xmm12; + RegXMM fpu_xmm13; + RegXMM fpu_xmm14; + RegXMM fpu_xmm15; + int8 fpu_rsrv4[96]; + int32 fpu_reserved1; +}; + +typedef struct ExceptionState ExceptionState; +struct ExceptionState { + uint32 trapno; + uint32 err; + uint64 faultvaddr; +}; + +typedef struct Mcontext Mcontext; +struct Mcontext { + ExceptionState es; + Regs ss; + FloatState fs; + byte pad_godefs_0[4]; +}; + +typedef struct Ucontext Ucontext; +struct Ucontext { + int32 uc_onstack; + uint32 uc_sigmask; + StackT uc_stack; + uint64 uc_link; + uint64 uc_mcsize; + Mcontext *uc_mcontext; +}; +#pragma pack off diff --git a/src/pkg/runtime/darwin/amd64/rt0.s b/src/pkg/runtime/darwin/amd64/rt0.s new file mode 100644 index 000000000..4cfab5876 --- /dev/null +++ b/src/pkg/runtime/darwin/amd64/rt0.s @@ -0,0 +1,10 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Darwin and Linux use the same linkage to main + +TEXT _rt0_amd64_darwin(SB),7,$-8 + MOVQ $_rt0_amd64(SB), AX + MOVQ SP, DI + JMP AX diff --git a/src/pkg/runtime/darwin/amd64/signal.c b/src/pkg/runtime/darwin/amd64/signal.c new file mode 100644 index 000000000..036a3aca7 --- /dev/null +++ b/src/pkg/runtime/darwin/amd64/signal.c @@ -0,0 +1,204 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "runtime.h" +#include "defs.h" +#include "os.h" +#include "signals.h" + +void +runtime·dumpregs(Regs *r) +{ + runtime·printf("rax %X\n", r->rax); + runtime·printf("rbx %X\n", r->rbx); + runtime·printf("rcx %X\n", r->rcx); + runtime·printf("rdx %X\n", r->rdx); + runtime·printf("rdi %X\n", r->rdi); + runtime·printf("rsi %X\n", r->rsi); + runtime·printf("rbp %X\n", r->rbp); + runtime·printf("rsp %X\n", r->rsp); + runtime·printf("r8 %X\n", r->r8 ); + runtime·printf("r9 %X\n", r->r9 ); + runtime·printf("r10 %X\n", r->r10); + runtime·printf("r11 %X\n", r->r11); + runtime·printf("r12 %X\n", r->r12); + runtime·printf("r13 %X\n", r->r13); + runtime·printf("r14 %X\n", r->r14); + runtime·printf("r15 %X\n", r->r15); + runtime·printf("rip %X\n", r->rip); + runtime·printf("rflags %X\n", r->rflags); + runtime·printf("cs %X\n", r->cs); + runtime·printf("fs %X\n", r->fs); + runtime·printf("gs %X\n", r->gs); +} + +String +runtime·signame(int32 sig) +{ + if(sig < 0 || sig >= NSIG) + return runtime·emptystring; + return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name); +} + +void +runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) +{ + Ucontext *uc; + Mcontext *mc; + Regs *r; + uintptr *sp; + byte *pc; + + uc = context; + mc = uc->uc_mcontext; + r = &mc->ss; + + if(sig == SIGPROF) { + runtime·sigprof((uint8*)r->rip, (uint8*)r->rsp, nil, gp); + return; + } + + if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) { + // Work around Leopard bug that doesn't set FPE_INTDIV. + // Look at instruction to see if it is a divide. + // Not necessary in Snow Leopard (si_code will be != 0). + if(sig == SIGFPE && info->si_code == 0) { + pc = (byte*)r->rip; + if((pc[0]&0xF0) == 0x40) // 64-bit REX prefix + pc++; + else if(pc[0] == 0x66) // 16-bit instruction prefix + pc++; + if(pc[0] == 0xF6 || pc[0] == 0xF7) + info->si_code = FPE_INTDIV; + } + + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp->sig = sig; + gp->sigcode0 = info->si_code; + gp->sigcode1 = (uintptr)info->si_addr; + gp->sigpc = r->rip; + + // Only push runtime·sigpanic if r->rip != 0. + // If r->rip == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime·sigpanic instead. + // (Otherwise the trace will end at runtime·sigpanic and we + // won't get to see who faulted.) + if(r->rip != 0) { + sp = (uintptr*)r->rsp; + *--sp = r->rip; + r->rsp = (uintptr)sp; + } + r->rip = (uintptr)runtime·sigpanic; + return; + } + + if(runtime·sigtab[sig].flags & SigQueue) { + if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore)) + return; + runtime·exit(2); // SIGINT, SIGTERM, etc + } + + if(runtime·panicking) // traceback already printed + runtime·exit(2); + runtime·panicking = 1; + + if(sig < 0 || sig >= NSIG){ + runtime·printf("Signal %d\n", sig); + }else{ + runtime·printf("%s\n", runtime·sigtab[sig].name); + } + + runtime·printf("pc: %X\n", r->rip); + runtime·printf("\n"); + + if(runtime·gotraceback()){ + runtime·traceback((void*)r->rip, (void*)r->rsp, 0, gp); + runtime·tracebackothers(gp); + runtime·dumpregs(r); + } + + runtime·exit(2); +} + +void +runtime·sigignore(int32, Siginfo*, void*) +{ +} + +void +runtime·signalstack(byte *p, int32 n) +{ + StackT st; + + st.ss_sp = p; + st.ss_size = n; + st.ss_flags = 0; + runtime·sigaltstack(&st, nil); +} + +static void +sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) +{ + Sigaction sa; + + runtime·memclr((byte*)&sa, sizeof sa); + sa.sa_flags = SA_SIGINFO|SA_ONSTACK; + if(restart) + sa.sa_flags |= SA_RESTART; + sa.sa_mask = ~0ULL; + sa.sa_tramp = (uintptr)runtime·sigtramp; // runtime·sigtramp's job is to call into real handler + sa.__sigaction_u.__sa_sigaction = (uintptr)fn; + runtime·sigaction(i, &sa, nil); +} + +void +runtime·initsig(int32 queue) +{ + int32 i; + void *fn; + + runtime·siginit(); + + for(i = 0; i<NSIG; i++) { + if(runtime·sigtab[i].flags) { + if((runtime·sigtab[i].flags & SigQueue) != queue) + continue; + if(runtime·sigtab[i].flags & (SigCatch | SigQueue)) + fn = runtime·sighandler; + else + fn = runtime·sigignore; + sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0); + } + } +} + +void +runtime·resetcpuprofiler(int32 hz) +{ + Itimerval it; + + runtime·memclr((byte*)&it, sizeof it); + if(hz == 0) { + runtime·setitimer(ITIMER_PROF, &it, nil); + sigaction(SIGPROF, SIG_IGN, true); + } else { + sigaction(SIGPROF, runtime·sighandler, true); + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 1000000 / hz; + it.it_value = it.it_interval; + runtime·setitimer(ITIMER_PROF, &it, nil); + } + m->profilehz = hz; +} + +void +os·sigpipe(void) +{ + sigaction(SIGPIPE, SIG_DFL, false); + runtime·raisesigpipe(); +} diff --git a/src/pkg/runtime/darwin/amd64/sys.s b/src/pkg/runtime/darwin/amd64/sys.s new file mode 100644 index 000000000..8d1b20f11 --- /dev/null +++ b/src/pkg/runtime/darwin/amd64/sys.s @@ -0,0 +1,295 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +// System calls and other sys.stuff for AMD64, Darwin +// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228 +// or /usr/include/sys/syscall.h (on a Mac) for system call numbers. +// +// The low 24 bits are the system call number. +// The high 8 bits specify the kind of system call: 1=Mach, 2=BSD, 3=Machine-Dependent. +// + +#include "amd64/asm.h" + +// Exit the entire program (like C exit) +TEXT runtime·exit(SB),7,$0 + MOVL 8(SP), DI // arg 1 exit status + MOVL $(0x2000000+1), AX // syscall entry + SYSCALL + CALL runtime·notok(SB) + RET + +// Exit this OS thread (like pthread_exit, which eventually +// calls __bsdthread_terminate). +TEXT runtime·exit1(SB),7,$0 + MOVL 8(SP), DI // arg 1 exit status + MOVL $(0x2000000+361), AX // syscall entry + SYSCALL + CALL runtime·notok(SB) + RET + +TEXT runtime·write(SB),7,$0 + MOVL 8(SP), DI // arg 1 fd + MOVQ 16(SP), SI // arg 2 buf + MOVL 24(SP), DX // arg 3 count + MOVL $(0x2000000+4), AX // syscall entry + SYSCALL + RET + +TEXT runtime·raisesigpipe(SB),7,$24 + get_tls(CX) + MOVQ m(CX), DX + MOVL $13, DI // arg 1 SIGPIPE + MOVQ m_procid(DX), SI // arg 2 thread_port + MOVL $(0x2000000+328), AX // syscall entry __pthread_kill + SYSCALL + RET + +TEXT runtime·setitimer(SB), 7, $0 + MOVL 8(SP), DI + MOVQ 16(SP), SI + MOVQ 24(SP), DX + MOVL $(0x2000000+83), AX // syscall entry + SYSCALL + RET + +// void gettime(int64 *sec, int32 *usec) +TEXT runtime·gettime(SB), 7, $32 + MOVQ SP, DI // must be non-nil, unused + MOVQ $0, SI + MOVL $(0x2000000+116), AX + SYSCALL + MOVQ sec+0(FP), DI + MOVQ AX, (DI) + MOVQ usec+8(FP), DI + MOVL DX, (DI) + RET + +TEXT runtime·sigaction(SB),7,$0 + MOVL 8(SP), DI // arg 1 sig + MOVQ 16(SP), SI // arg 2 act + MOVQ 24(SP), DX // arg 3 oact + MOVQ 24(SP), CX // arg 3 oact + MOVQ 24(SP), R10 // arg 3 oact + MOVL $(0x2000000+46), AX // syscall entry + SYSCALL + JCC 2(PC) + CALL runtime·notok(SB) + RET + +TEXT runtime·sigtramp(SB),7,$64 + get_tls(BX) + + // save g + MOVQ g(BX), R10 + MOVQ R10, 48(SP) + + // g = m->gsignal + MOVQ m(BX), BP + MOVQ m_gsignal(BP), BP + MOVQ BP, g(BX) + + MOVL DX, 0(SP) + MOVQ CX, 8(SP) + MOVQ R8, 16(SP) + MOVQ R10, 24(SP) + + MOVQ R8, 32(SP) // save ucontext + MOVQ SI, 40(SP) // save infostyle + CALL DI + + // restore g + get_tls(BX) + MOVQ 48(SP), R10 + MOVQ R10, g(BX) + + // call sigreturn + MOVL $(0x2000000+184), AX // sigreturn(ucontext, infostyle) + MOVQ 32(SP), DI // saved ucontext + MOVQ 40(SP), SI // saved infostyle + SYSCALL + INT $3 // not reached + +TEXT runtime·mmap(SB),7,$0 + MOVQ 8(SP), DI // arg 1 addr + MOVQ 16(SP), SI // arg 2 len + MOVL 24(SP), DX // arg 3 prot + MOVL 28(SP), R10 // arg 4 flags + MOVL 32(SP), R8 // arg 5 fid + MOVL 36(SP), R9 // arg 6 offset + MOVL $(0x2000000+197), AX // syscall entry + SYSCALL + RET + +TEXT runtime·munmap(SB),7,$0 + MOVQ 8(SP), DI // arg 1 addr + MOVQ 16(SP), SI // arg 2 len + MOVL $(0x2000000+73), AX // syscall entry + SYSCALL + JCC 2(PC) + CALL runtime·notok(SB) + RET + +TEXT runtime·notok(SB),7,$0 + MOVL $0xf1, BP + MOVQ BP, (BP) + RET + +TEXT runtime·sigaltstack(SB),7,$0 + MOVQ new+8(SP), DI + MOVQ old+16(SP), SI + MOVQ $(0x2000000+53), AX + SYSCALL + JCC 2(PC) + CALL runtime·notok(SB) + RET + +// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void)) +TEXT runtime·bsdthread_create(SB),7,$0 + // Set up arguments to bsdthread_create system call. + // The ones in quotes pass through to the thread callback + // uninterpreted, so we can put whatever we want there. + MOVQ fn+32(SP), DI // "func" + MOVQ mm+16(SP), SI // "arg" + MOVQ stk+8(SP), DX // stack + MOVQ gg+24(SP), R10 // "pthread" + MOVQ $0x01000000, R8 // flags = PTHREAD_START_CUSTOM + MOVQ $0, R9 // paranoia + MOVQ $(0x2000000+360), AX // bsdthread_create + SYSCALL + JCC 3(PC) + NEGL AX + RET + MOVL $0, AX + RET + +// The thread that bsdthread_create creates starts executing here, +// because we registered this function using bsdthread_register +// at startup. +// DI = "pthread" +// SI = mach thread port +// DX = "func" (= fn) +// CX = "arg" (= m) +// R8 = stack +// R9 = flags (= 0) +// SP = stack - C_64_REDZONE_LEN (= stack - 128) +TEXT runtime·bsdthread_start(SB),7,$0 + MOVQ R8, SP // empirically, SP is very wrong but R8 is right + + PUSHQ DX + PUSHQ CX + PUSHQ SI + + // set up thread local storage pointing at m->tls. + LEAQ m_tls(CX), DI + CALL runtime·settls(SB) + + POPQ SI + POPQ CX + POPQ DX + + get_tls(BX) + MOVQ CX, m(BX) + MOVQ SI, m_procid(CX) // thread port is m->procid + MOVQ m_g0(CX), AX + MOVQ AX, g(BX) + CALL runtime·stackcheck(SB) // smashes AX, CX + CALL DX // fn + CALL runtime·exit1(SB) + RET + +// void bsdthread_register(void) +// registers callbacks for threadstart (see bsdthread_create above +// and wqthread and pthsize (not used). returns 0 on success. +TEXT runtime·bsdthread_register(SB),7,$0 + MOVQ $runtime·bsdthread_start(SB), DI // threadstart + MOVQ $0, SI // wqthread, not used by us + MOVQ $0, DX // pthsize, not used by us + MOVQ $0, R10 // dummy_value [sic] + MOVQ $0, R8 // targetconc_ptr + MOVQ $0, R9 // dispatchqueue_offset + MOVQ $(0x2000000+366), AX // bsdthread_register + SYSCALL + JCC 2(PC) + CALL runtime·notok(SB) + RET + +// Mach system calls use 0x1000000 instead of the BSD's 0x2000000. + +// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32) +TEXT runtime·mach_msg_trap(SB),7,$0 + MOVQ 8(SP), DI + MOVL 16(SP), SI + MOVL 20(SP), DX + MOVL 24(SP), R10 + MOVL 28(SP), R8 + MOVL 32(SP), R9 + MOVL 36(SP), R11 + PUSHQ R11 // seventh arg, on stack + MOVL $(0x1000000+31), AX // mach_msg_trap + SYSCALL + POPQ R11 + RET + +TEXT runtime·mach_task_self(SB),7,$0 + MOVL $(0x1000000+28), AX // task_self_trap + SYSCALL + RET + +TEXT runtime·mach_thread_self(SB),7,$0 + MOVL $(0x1000000+27), AX // thread_self_trap + SYSCALL + RET + +TEXT runtime·mach_reply_port(SB),7,$0 + MOVL $(0x1000000+26), AX // mach_reply_port + SYSCALL + RET + +// Mach provides trap versions of the semaphore ops, +// instead of requiring the use of RPC. + +// uint32 mach_semaphore_wait(uint32) +TEXT runtime·mach_semaphore_wait(SB),7,$0 + MOVL 8(SP), DI + MOVL $(0x1000000+36), AX // semaphore_wait_trap + SYSCALL + RET + +// uint32 mach_semaphore_timedwait(uint32, uint32, uint32) +TEXT runtime·mach_semaphore_timedwait(SB),7,$0 + MOVL 8(SP), DI + MOVL 12(SP), SI + MOVL 16(SP), DX + MOVL $(0x1000000+38), AX // semaphore_timedwait_trap + SYSCALL + RET + +// uint32 mach_semaphore_signal(uint32) +TEXT runtime·mach_semaphore_signal(SB),7,$0 + MOVL 8(SP), DI + MOVL $(0x1000000+33), AX // semaphore_signal_trap + SYSCALL + RET + +// uint32 mach_semaphore_signal_all(uint32) +TEXT runtime·mach_semaphore_signal_all(SB),7,$0 + MOVL 8(SP), DI + MOVL $(0x1000000+34), AX // semaphore_signal_all_trap + SYSCALL + RET + +// set tls base to DI +TEXT runtime·settls(SB),7,$32 + /* + * Same as in ../386/sys.s:/ugliness, different constant. + * See ../../../../libcgo/darwin_amd64.c for the derivation + * of the constant. + */ + SUBQ $0x8a0, DI + + MOVL $(0x3000000+3), AX // thread_fast_set_cthread_self - machdep call #3 + SYSCALL + RET diff --git a/src/pkg/runtime/darwin/defs.c b/src/pkg/runtime/darwin/defs.c new file mode 100644 index 000000000..032a6bcbb --- /dev/null +++ b/src/pkg/runtime/darwin/defs.c @@ -0,0 +1,159 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* + * Input to godefs. + * + godefs -f -m64 defs.c >amd64/defs.h + godefs -f -m32 defs.c >386/defs.h + */ + +#define __DARWIN_UNIX03 0 + +#include <mach/mach.h> +#include <mach/message.h> +#include <sys/types.h> +#include <sys/time.h> +#include <signal.h> +#include <sys/mman.h> + +enum { + $PROT_NONE = PROT_NONE, + $PROT_READ = PROT_READ, + $PROT_WRITE = PROT_WRITE, + $PROT_EXEC = PROT_EXEC, + + $MAP_ANON = MAP_ANON, + $MAP_PRIVATE = MAP_PRIVATE, + $MAP_FIXED = MAP_FIXED, + + $MACH_MSG_TYPE_MOVE_RECEIVE = MACH_MSG_TYPE_MOVE_RECEIVE, + $MACH_MSG_TYPE_MOVE_SEND = MACH_MSG_TYPE_MOVE_SEND, + $MACH_MSG_TYPE_MOVE_SEND_ONCE = MACH_MSG_TYPE_MOVE_SEND_ONCE, + $MACH_MSG_TYPE_COPY_SEND = MACH_MSG_TYPE_COPY_SEND, + $MACH_MSG_TYPE_MAKE_SEND = MACH_MSG_TYPE_MAKE_SEND, + $MACH_MSG_TYPE_MAKE_SEND_ONCE = MACH_MSG_TYPE_MAKE_SEND_ONCE, + $MACH_MSG_TYPE_COPY_RECEIVE = MACH_MSG_TYPE_COPY_RECEIVE, + + $MACH_MSG_PORT_DESCRIPTOR = MACH_MSG_PORT_DESCRIPTOR, + $MACH_MSG_OOL_DESCRIPTOR = MACH_MSG_OOL_DESCRIPTOR, + $MACH_MSG_OOL_PORTS_DESCRIPTOR = MACH_MSG_OOL_PORTS_DESCRIPTOR, + $MACH_MSG_OOL_VOLATILE_DESCRIPTOR = MACH_MSG_OOL_VOLATILE_DESCRIPTOR, + + $MACH_MSGH_BITS_COMPLEX = MACH_MSGH_BITS_COMPLEX, + + $MACH_SEND_MSG = MACH_SEND_MSG, + $MACH_RCV_MSG = MACH_RCV_MSG, + $MACH_RCV_LARGE = MACH_RCV_LARGE, + + $MACH_SEND_TIMEOUT = MACH_SEND_TIMEOUT, + $MACH_SEND_INTERRUPT = MACH_SEND_INTERRUPT, + $MACH_SEND_CANCEL = MACH_SEND_CANCEL, + $MACH_SEND_ALWAYS = MACH_SEND_ALWAYS, + $MACH_SEND_TRAILER = MACH_SEND_TRAILER, + $MACH_RCV_TIMEOUT = MACH_RCV_TIMEOUT, + $MACH_RCV_NOTIFY = MACH_RCV_NOTIFY, + $MACH_RCV_INTERRUPT = MACH_RCV_INTERRUPT, + $MACH_RCV_OVERWRITE = MACH_RCV_OVERWRITE, + + $NDR_PROTOCOL_2_0 = NDR_PROTOCOL_2_0, + $NDR_INT_BIG_ENDIAN = NDR_INT_BIG_ENDIAN, + $NDR_INT_LITTLE_ENDIAN = NDR_INT_LITTLE_ENDIAN, + $NDR_FLOAT_IEEE = NDR_FLOAT_IEEE, + $NDR_CHAR_ASCII = NDR_CHAR_ASCII, + + $SA_SIGINFO = SA_SIGINFO, + $SA_RESTART = SA_RESTART, + $SA_ONSTACK = SA_ONSTACK, + $SA_USERTRAMP = SA_USERTRAMP, + $SA_64REGSET = SA_64REGSET, + + $SIGHUP = SIGHUP, + $SIGINT = SIGINT, + $SIGQUIT = SIGQUIT, + $SIGILL = SIGILL, + $SIGTRAP = SIGTRAP, + $SIGABRT = SIGABRT, + $SIGEMT = SIGEMT, + $SIGFPE = SIGFPE, + $SIGKILL = SIGKILL, + $SIGBUS = SIGBUS, + $SIGSEGV = SIGSEGV, + $SIGSYS = SIGSYS, + $SIGPIPE = SIGPIPE, + $SIGALRM = SIGALRM, + $SIGTERM = SIGTERM, + $SIGURG = SIGURG, + $SIGSTOP = SIGSTOP, + $SIGTSTP = SIGTSTP, + $SIGCONT = SIGCONT, + $SIGCHLD = SIGCHLD, + $SIGTTIN = SIGTTIN, + $SIGTTOU = SIGTTOU, + $SIGIO = SIGIO, + $SIGXCPU = SIGXCPU, + $SIGXFSZ = SIGXFSZ, + $SIGVTALRM = SIGVTALRM, + $SIGPROF = SIGPROF, + $SIGWINCH = SIGWINCH, + $SIGINFO = SIGINFO, + $SIGUSR1 = SIGUSR1, + $SIGUSR2 = SIGUSR2, + + $FPE_INTDIV = FPE_INTDIV, + $FPE_INTOVF = FPE_INTOVF, + $FPE_FLTDIV = FPE_FLTDIV, + $FPE_FLTOVF = FPE_FLTOVF, + $FPE_FLTUND = FPE_FLTUND, + $FPE_FLTRES = FPE_FLTRES, + $FPE_FLTINV = FPE_FLTINV, + $FPE_FLTSUB = FPE_FLTSUB, + + $BUS_ADRALN = BUS_ADRALN, + $BUS_ADRERR = BUS_ADRERR, + $BUS_OBJERR = BUS_OBJERR, + + $SEGV_MAPERR = SEGV_MAPERR, + $SEGV_ACCERR = SEGV_ACCERR, + + $ITIMER_REAL = ITIMER_REAL, + $ITIMER_VIRTUAL = ITIMER_VIRTUAL, + $ITIMER_PROF = ITIMER_PROF, +}; + +typedef mach_msg_body_t $MachBody; +typedef mach_msg_header_t $MachHeader; +typedef NDR_record_t $MachNDR; +typedef mach_msg_port_descriptor_t $MachPort; + +typedef stack_t $StackT; +typedef union __sigaction_u $Sighandler; + +typedef struct __sigaction $Sigaction; // used in syscalls +// typedef struct sigaction $Sigaction; // used by the C library +typedef union sigval $Sigval; +typedef siginfo_t $Siginfo; +typedef struct timeval $Timeval; +typedef struct itimerval $Itimerval; + +typedef struct fp_control $FPControl; +typedef struct fp_status $FPStatus; +typedef struct mmst_reg $RegMMST; +typedef struct xmm_reg $RegXMM; + +#ifdef __LP64__ +// amd64 +typedef x86_thread_state64_t $Regs; +typedef x86_float_state64_t $FloatState; +typedef x86_exception_state64_t $ExceptionState; +typedef struct mcontext64 $Mcontext; +#else +// 386 +typedef x86_thread_state32_t $Regs; +typedef x86_float_state32_t $FloatState; +typedef x86_exception_state32_t $ExceptionState; +typedef struct mcontext32 $Mcontext; +#endif + +typedef ucontext_t $Ucontext; diff --git a/src/pkg/runtime/darwin/mem.c b/src/pkg/runtime/darwin/mem.c new file mode 100644 index 000000000..935c032bc --- /dev/null +++ b/src/pkg/runtime/darwin/mem.c @@ -0,0 +1,55 @@ +#include "runtime.h" +#include "defs.h" +#include "os.h" +#include "malloc.h" + +void* +runtime·SysAlloc(uintptr n) +{ + void *v; + + mstats.sys += n; + v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0); + if(v < (void*)4096) + return nil; + return v; +} + +void +runtime·SysUnused(void *v, uintptr n) +{ + USED(v); + USED(n); + // TODO(rsc): call madvise MADV_DONTNEED +} + +void +runtime·SysFree(void *v, uintptr n) +{ + mstats.sys -= n; + runtime·munmap(v, n); +} + +void* +runtime·SysReserve(void *v, uintptr n) +{ + return runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); +} + +enum +{ + ENOMEM = 12, +}; + +void +runtime·SysMap(void *v, uintptr n) +{ + void *p; + + mstats.sys += n; + p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0); + if(p == (void*)-ENOMEM) + runtime·throw("runtime: out of memory"); + if(p != v) + runtime·throw("runtime: cannot map pages in arena address space"); +} diff --git a/src/pkg/runtime/darwin/os.h b/src/pkg/runtime/darwin/os.h new file mode 100644 index 000000000..db3c2e8a7 --- /dev/null +++ b/src/pkg/runtime/darwin/os.h @@ -0,0 +1,31 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#define SIG_DFL ((void*)0) +#define SIG_IGN ((void*)1) + +int32 runtime·bsdthread_create(void*, M*, G*, void(*)(void)); +void runtime·bsdthread_register(void); +int32 runtime·mach_msg_trap(MachHeader*, int32, uint32, uint32, uint32, uint32, uint32); +uint32 runtime·mach_reply_port(void); +void runtime·mach_semacquire(uint32); +uint32 runtime·mach_semcreate(void); +void runtime·mach_semdestroy(uint32); +void runtime·mach_semrelease(uint32); +void runtime·mach_semreset(uint32); +uint32 runtime·mach_task_self(void); +uint32 runtime·mach_task_self(void); +uint32 runtime·mach_thread_self(void); +uint32 runtime·mach_thread_self(void); + +struct Sigaction; +void runtime·sigaction(uintptr, struct Sigaction*, struct Sigaction*); + +struct StackT; +void runtime·sigaltstack(struct StackT*, struct StackT*); +void runtime·sigtramp(void); +void runtime·sigpanic(void); +void runtime·setitimer(int32, Itimerval*, Itimerval*); + +void runtime·raisesigpipe(void); diff --git a/src/pkg/runtime/darwin/signals.h b/src/pkg/runtime/darwin/signals.h new file mode 100644 index 000000000..035027fad --- /dev/null +++ b/src/pkg/runtime/darwin/signals.h @@ -0,0 +1,51 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#define C SigCatch +#define I SigIgnore +#define R SigRestart +#define Q SigQueue +#define P SigPanic + +SigTab runtime·sigtab[] = { + /* 0 */ 0, "SIGNONE: no trap", + /* 1 */ Q+R, "SIGHUP: terminal line hangup", + /* 2 */ Q+R, "SIGINT: interrupt", + /* 3 */ C, "SIGQUIT: quit", + /* 4 */ C, "SIGILL: illegal instruction", + /* 5 */ C, "SIGTRAP: trace trap", /* used by panic and array out of bounds, etc. */ + /* 6 */ C, "SIGABRT: abort", + /* 7 */ C, "SIGEMT: emulate instruction executed", + /* 8 */ C+P, "SIGFPE: floating-point exception", + /* 9 */ 0, "SIGKILL: kill", + /* 10 */ C+P, "SIGBUS: bus error", + /* 11 */ C+P, "SIGSEGV: segmentation violation", + /* 12 */ C, "SIGSYS: bad system call", + /* 13 */ I, "SIGPIPE: write to broken pipe", + /* 14 */ Q+I+R, "SIGALRM: alarm clock", + /* 15 */ Q+R, "SIGTERM: termination", + /* 16 */ Q+I+R, "SIGURG: urgent condition on socket", + /* 17 */ 0, "SIGSTOP: stop", + /* 18 */ Q+I+R, "SIGTSTP: keyboard stop", + /* 19 */ 0, "SIGCONT: continue after stop", + /* 20 */ Q+I+R, "SIGCHLD: child status has changed", + /* 21 */ Q+I+R, "SIGTTIN: background read from tty", + /* 22 */ Q+I+R, "SIGTTOU: background write to tty", + /* 23 */ Q+I+R, "SIGIO: i/o now possible", + /* 24 */ Q+I+R, "SIGXCPU: cpu limit exceeded", + /* 25 */ Q+I+R, "SIGXFSZ: file size limit exceeded", + /* 26 */ Q+I+R, "SIGVTALRM: virtual alarm clock", + /* 27 */ Q+I+R, "SIGPROF: profiling alarm clock", + /* 28 */ Q+I+R, "SIGWINCH: window size change", + /* 29 */ Q+I+R, "SIGINFO: status request from keyboard", + /* 30 */ Q+I+R, "SIGUSR1: user-defined signal 1", + /* 31 */ Q+I+R, "SIGUSR2: user-defined signal 2", +}; +#undef C +#undef I +#undef R +#undef Q +#undef P + +#define NSIG 32 diff --git a/src/pkg/runtime/darwin/thread.c b/src/pkg/runtime/darwin/thread.c new file mode 100644 index 000000000..6733e815e --- /dev/null +++ b/src/pkg/runtime/darwin/thread.c @@ -0,0 +1,484 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "runtime.h" +#include "defs.h" +#include "os.h" +#include "stack.h" + +extern SigTab runtime·sigtab[]; + +static void +unimplemented(int8 *name) +{ + runtime·prints(name); + runtime·prints(" not implemented\n"); + *(int32*)1231 = 1231; +} + +// Thread-safe allocation of a semaphore. +// Psema points at a kernel semaphore key. +// It starts out zero, meaning no semaphore. +// Fill it in, being careful of others calling initsema +// simultaneously. +static void +initsema(uint32 *psema) +{ + uint32 sema; + + if(*psema != 0) // already have one + return; + + sema = runtime·mach_semcreate(); + if(!runtime·cas(psema, 0, sema)){ + // Someone else filled it in. Use theirs. + runtime·mach_semdestroy(sema); + return; + } +} + + +// Blocking locks. + +// Implement Locks, using semaphores. +// l->key is the number of threads who want the lock. +// In a race, one thread increments l->key from 0 to 1 +// and the others increment it from >0 to >1. The thread +// who does the 0->1 increment gets the lock, and the +// others wait on the semaphore. When the 0->1 thread +// releases the lock by decrementing l->key, l->key will +// be >0, so it will increment the semaphore to wake up +// one of the others. This is the same algorithm used +// in Plan 9's user-level locks. + +void +runtime·lock(Lock *l) +{ + if(m->locks < 0) + runtime·throw("lock count"); + m->locks++; + + if(runtime·xadd(&l->key, 1) > 1) { // someone else has it; wait + // Allocate semaphore if needed. + if(l->sema == 0) + initsema(&l->sema); + runtime·mach_semacquire(l->sema); + } +} + +void +runtime·unlock(Lock *l) +{ + m->locks--; + if(m->locks < 0) + runtime·throw("lock count"); + + if(runtime·xadd(&l->key, -1) > 0) { // someone else is waiting + // Allocate semaphore if needed. + if(l->sema == 0) + initsema(&l->sema); + runtime·mach_semrelease(l->sema); + } +} + +static void +destroylock(Lock *l) +{ + if(l->sema != 0) { + runtime·mach_semdestroy(l->sema); + l->sema = 0; + } +} + +// User-level semaphore implementation: +// try to do the operations in user space on u, +// but when it's time to block, fall back on the kernel semaphore k. +// This is the same algorithm used in Plan 9. +void +runtime·usemacquire(Usema *s) +{ + if((int32)runtime·xadd(&s->u, -1) < 0) { + if(s->k == 0) + initsema(&s->k); + runtime·mach_semacquire(s->k); + } +} + +void +runtime·usemrelease(Usema *s) +{ + if((int32)runtime·xadd(&s->u, 1) <= 0) { + if(s->k == 0) + initsema(&s->k); + runtime·mach_semrelease(s->k); + } +} + + +// Event notifications. +void +runtime·noteclear(Note *n) +{ + n->wakeup = 0; +} + +void +runtime·notesleep(Note *n) +{ + while(!n->wakeup) + runtime·usemacquire(&n->sema); +} + +void +runtime·notewakeup(Note *n) +{ + n->wakeup = 1; + runtime·usemrelease(&n->sema); +} + + +// BSD interface for threading. +void +runtime·osinit(void) +{ + // Register our thread-creation callback (see {amd64,386}/sys.s) + // but only if we're not using cgo. If we are using cgo we need + // to let the C pthread libary install its own thread-creation callback. + if(!runtime·iscgo) + runtime·bsdthread_register(); + runtime·destroylock = destroylock; +} + +void +runtime·goenvs(void) +{ + runtime·goenvs_unix(); +} + +void +runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) +{ + int32 errno; + + m->tls[0] = m->id; // so 386 asm can find it + if(0){ + runtime·printf("newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n", + stk, m, g, fn, m->id, m->tls[0], &m); + } + if((errno = runtime·bsdthread_create(stk, m, g, fn)) < 0) { + runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), -errno); + runtime·throw("runtime.newosproc"); + } +} + +// Called to initialize a new m (including the bootstrap m). +void +runtime·minit(void) +{ + // Initialize signal handling. + m->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K + runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024); +} + +// Mach IPC, to get at semaphores +// Definitions are in /usr/include/mach on a Mac. + +static void +macherror(int32 r, int8 *fn) +{ + runtime·printf("mach error %s: %d\n", fn, r); + runtime·throw("mach error"); +} + +enum +{ + DebugMach = 0 +}; + +static MachNDR zerondr; + +#define MACH_MSGH_BITS(a, b) ((a) | ((b)<<8)) + +static int32 +mach_msg(MachHeader *h, + int32 op, + uint32 send_size, + uint32 rcv_size, + uint32 rcv_name, + uint32 timeout, + uint32 notify) +{ + // TODO: Loop on interrupt. + return runtime·mach_msg_trap(h, op, send_size, rcv_size, rcv_name, timeout, notify); +} + +// Mach RPC (MIG) + +enum +{ + MinMachMsg = 48, + Reply = 100, +}; + +#pragma pack on +typedef struct CodeMsg CodeMsg; +struct CodeMsg +{ + MachHeader h; + MachNDR NDR; + int32 code; +}; +#pragma pack off + +static int32 +machcall(MachHeader *h, int32 maxsize, int32 rxsize) +{ + uint32 *p; + int32 i, ret, id; + uint32 port; + CodeMsg *c; + + if((port = m->machport) == 0){ + port = runtime·mach_reply_port(); + m->machport = port; + } + + h->msgh_bits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); + h->msgh_local_port = port; + h->msgh_reserved = 0; + id = h->msgh_id; + + if(DebugMach){ + p = (uint32*)h; + runtime·prints("send:\t"); + for(i=0; i<h->msgh_size/sizeof(p[0]); i++){ + runtime·prints(" "); + runtime·printpointer((void*)p[i]); + if(i%8 == 7) + runtime·prints("\n\t"); + } + if(i%8) + runtime·prints("\n"); + } + + ret = mach_msg(h, MACH_SEND_MSG|MACH_RCV_MSG, + h->msgh_size, maxsize, port, 0, 0); + if(ret != 0){ + if(DebugMach){ + runtime·prints("mach_msg error "); + runtime·printint(ret); + runtime·prints("\n"); + } + return ret; + } + + if(DebugMach){ + p = (uint32*)h; + runtime·prints("recv:\t"); + for(i=0; i<h->msgh_size/sizeof(p[0]); i++){ + runtime·prints(" "); + runtime·printpointer((void*)p[i]); + if(i%8 == 7) + runtime·prints("\n\t"); + } + if(i%8) + runtime·prints("\n"); + } + + if(h->msgh_id != id+Reply){ + if(DebugMach){ + runtime·prints("mach_msg reply id mismatch "); + runtime·printint(h->msgh_id); + runtime·prints(" != "); + runtime·printint(id+Reply); + runtime·prints("\n"); + } + return -303; // MIG_REPLY_MISMATCH + } + + // Look for a response giving the return value. + // Any call can send this back with an error, + // and some calls only have return values so they + // send it back on success too. I don't quite see how + // you know it's one of these and not the full response + // format, so just look if the message is right. + c = (CodeMsg*)h; + if(h->msgh_size == sizeof(CodeMsg) + && !(h->msgh_bits & MACH_MSGH_BITS_COMPLEX)){ + if(DebugMach){ + runtime·prints("mig result "); + runtime·printint(c->code); + runtime·prints("\n"); + } + return c->code; + } + + if(h->msgh_size != rxsize){ + if(DebugMach){ + runtime·prints("mach_msg reply size mismatch "); + runtime·printint(h->msgh_size); + runtime·prints(" != "); + runtime·printint(rxsize); + runtime·prints("\n"); + } + return -307; // MIG_ARRAY_TOO_LARGE + } + + return 0; +} + + +// Semaphores! + +enum +{ + Tmach_semcreate = 3418, + Rmach_semcreate = Tmach_semcreate + Reply, + + Tmach_semdestroy = 3419, + Rmach_semdestroy = Tmach_semdestroy + Reply, + + // Mach calls that get interrupted by Unix signals + // return this error code. We retry them. + KERN_ABORTED = 14, +}; + +typedef struct Tmach_semcreateMsg Tmach_semcreateMsg; +typedef struct Rmach_semcreateMsg Rmach_semcreateMsg; +typedef struct Tmach_semdestroyMsg Tmach_semdestroyMsg; +// Rmach_semdestroyMsg = CodeMsg + +#pragma pack on +struct Tmach_semcreateMsg +{ + MachHeader h; + MachNDR ndr; + int32 policy; + int32 value; +}; + +struct Rmach_semcreateMsg +{ + MachHeader h; + MachBody body; + MachPort semaphore; +}; + +struct Tmach_semdestroyMsg +{ + MachHeader h; + MachBody body; + MachPort semaphore; +}; +#pragma pack off + +uint32 +runtime·mach_semcreate(void) +{ + union { + Tmach_semcreateMsg tx; + Rmach_semcreateMsg rx; + uint8 pad[MinMachMsg]; + } m; + int32 r; + + m.tx.h.msgh_bits = 0; + m.tx.h.msgh_size = sizeof(m.tx); + m.tx.h.msgh_remote_port = runtime·mach_task_self(); + m.tx.h.msgh_id = Tmach_semcreate; + m.tx.ndr = zerondr; + + m.tx.policy = 0; // 0 = SYNC_POLICY_FIFO + m.tx.value = 0; + + while((r = machcall(&m.tx.h, sizeof m, sizeof(m.rx))) != 0){ + if(r == KERN_ABORTED) // interrupted + continue; + macherror(r, "semaphore_create"); + } + if(m.rx.body.msgh_descriptor_count != 1) + unimplemented("mach_semcreate desc count"); + return m.rx.semaphore.name; +} + +void +runtime·mach_semdestroy(uint32 sem) +{ + union { + Tmach_semdestroyMsg tx; + uint8 pad[MinMachMsg]; + } m; + int32 r; + + m.tx.h.msgh_bits = MACH_MSGH_BITS_COMPLEX; + m.tx.h.msgh_size = sizeof(m.tx); + m.tx.h.msgh_remote_port = runtime·mach_task_self(); + m.tx.h.msgh_id = Tmach_semdestroy; + m.tx.body.msgh_descriptor_count = 1; + m.tx.semaphore.name = sem; + m.tx.semaphore.disposition = MACH_MSG_TYPE_MOVE_SEND; + m.tx.semaphore.type = 0; + + while((r = machcall(&m.tx.h, sizeof m, 0)) != 0){ + if(r == KERN_ABORTED) // interrupted + continue; + macherror(r, "semaphore_destroy"); + } +} + +// The other calls have simple system call traps in sys.s +int32 runtime·mach_semaphore_wait(uint32 sema); +int32 runtime·mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec); +int32 runtime·mach_semaphore_signal(uint32 sema); +int32 runtime·mach_semaphore_signal_all(uint32 sema); + +void +runtime·mach_semacquire(uint32 sem) +{ + int32 r; + + while((r = runtime·mach_semaphore_wait(sem)) != 0) { + if(r == KERN_ABORTED) // interrupted + continue; + macherror(r, "semaphore_wait"); + } +} + +void +runtime·mach_semrelease(uint32 sem) +{ + int32 r; + + while((r = runtime·mach_semaphore_signal(sem)) != 0) { + if(r == KERN_ABORTED) // interrupted + continue; + macherror(r, "semaphore_signal"); + } +} + +void +runtime·sigpanic(void) +{ + switch(g->sig) { + case SIGBUS: + if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) + runtime·panicstring("invalid memory address or nil pointer dereference"); + runtime·printf("unexpected fault address %p\n", g->sigcode1); + runtime·throw("fault"); + case SIGSEGV: + if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) + runtime·panicstring("invalid memory address or nil pointer dereference"); + runtime·printf("unexpected fault address %p\n", g->sigcode1); + runtime·throw("fault"); + case SIGFPE: + switch(g->sigcode0) { + case FPE_INTDIV: + runtime·panicstring("integer divide by zero"); + case FPE_INTOVF: + runtime·panicstring("integer overflow"); + } + runtime·panicstring("floating point error"); + } + runtime·panicstring(runtime·sigtab[g->sig].name); +} |