summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/darwin
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-09-13 13:13:40 +0200
committerOndřej Surý <ondrej@sury.org>2011-09-13 13:13:40 +0200
commit5ff4c17907d5b19510a62e08fd8d3b11e62b431d (patch)
treec0650497e988f47be9c6f2324fa692a52dea82e1 /src/pkg/runtime/darwin
parent80f18fc933cf3f3e829c5455a1023d69f7b86e52 (diff)
downloadgolang-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.h289
-rw-r--r--src/pkg/runtime/darwin/386/rt0.s8
-rw-r--r--src/pkg/runtime/darwin/386/signal.c194
-rw-r--r--src/pkg/runtime/darwin/386/sys.s311
-rw-r--r--src/pkg/runtime/darwin/amd64/defs.h305
-rw-r--r--src/pkg/runtime/darwin/amd64/rt0.s10
-rw-r--r--src/pkg/runtime/darwin/amd64/signal.c204
-rw-r--r--src/pkg/runtime/darwin/amd64/sys.s295
-rw-r--r--src/pkg/runtime/darwin/defs.c159
-rw-r--r--src/pkg/runtime/darwin/mem.c55
-rw-r--r--src/pkg/runtime/darwin/os.h31
-rw-r--r--src/pkg/runtime/darwin/signals.h51
-rw-r--r--src/pkg/runtime/darwin/thread.c484
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);
+}