From e9d62a6d81ee380acda593edec0d3a05295254ec Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 14 Mar 2013 11:35:13 -0700 Subject: runtime: refactor os-specific code thread_GOOS.c becomes os_GOOS.c. signal_GOOS_GOARCH.c becomes os_GOOS_GOARCH.c, but with non-GOARCH-specific code moved into os_GOOS.c. The actual arch-specific signal handler moves into signal_GOARCH.c to avoid per-GOOS duplication. New files signal_GOOS_GOARCH.h provide macros for accessing fields of the very system-specific signal info structs. Lots moving, but nothing changing. This is a preliminarly cleanup so I can work on the signal handling code to fix some open issues without having to make each change 13 times. Tested on Linux and OS X, 386 and amd64. Will fix Plan 9, Windows, and ARM after the fact if necessary. (Plan 9 and Windows should be fine; ARM will probably have some typos.) Net effect: -1081 lines of code. R=golang-dev, r CC=golang-dev https://golang.org/cl/7565048 --- src/pkg/runtime/os_darwin.c | 587 +++++++++++++++++++++++++++++++++ src/pkg/runtime/os_darwin.h | 6 - src/pkg/runtime/os_freebsd.c | 315 ++++++++++++++++++ src/pkg/runtime/os_freebsd.h | 6 - src/pkg/runtime/os_freebsd_arm.c | 23 ++ src/pkg/runtime/os_linux.c | 369 +++++++++++++++++++++ src/pkg/runtime/os_linux.h | 6 - src/pkg/runtime/os_linux_386.c | 37 +++ src/pkg/runtime/os_linux_arm.c | 82 +++++ src/pkg/runtime/os_netbsd.c | 360 ++++++++++++++++++++ src/pkg/runtime/os_netbsd.h | 6 - src/pkg/runtime/os_netbsd_386.c | 17 + src/pkg/runtime/os_netbsd_amd64.c | 18 + src/pkg/runtime/os_netbsd_arm.c | 32 ++ src/pkg/runtime/os_openbsd.c | 334 +++++++++++++++++++ src/pkg/runtime/os_openbsd.h | 6 - src/pkg/runtime/os_plan9.c | 344 +++++++++++++++++++ src/pkg/runtime/os_plan9.h | 1 - src/pkg/runtime/os_plan9_386.c | 120 +++++++ src/pkg/runtime/os_plan9_amd64.c | 127 +++++++ src/pkg/runtime/os_windows.c | 457 +++++++++++++++++++++++++ src/pkg/runtime/os_windows_386.c | 97 ++++++ src/pkg/runtime/os_windows_amd64.c | 104 ++++++ src/pkg/runtime/signal_386.c | 119 +++++++ src/pkg/runtime/signal_amd64.c | 129 ++++++++ src/pkg/runtime/signal_arm.c | 120 +++++++ src/pkg/runtime/signal_darwin_386.c | 155 --------- src/pkg/runtime/signal_darwin_386.h | 23 ++ src/pkg/runtime/signal_darwin_amd64.c | 165 --------- src/pkg/runtime/signal_darwin_amd64.h | 31 ++ src/pkg/runtime/signal_freebsd_386.c | 154 --------- src/pkg/runtime/signal_freebsd_386.h | 23 ++ src/pkg/runtime/signal_freebsd_amd64.c | 162 --------- src/pkg/runtime/signal_freebsd_amd64.h | 31 ++ src/pkg/runtime/signal_freebsd_arm.c | 193 ----------- src/pkg/runtime/signal_freebsd_arm.h | 27 ++ src/pkg/runtime/signal_linux_386.c | 180 ---------- src/pkg/runtime/signal_linux_386.h | 24 ++ src/pkg/runtime/signal_linux_amd64.c | 162 --------- src/pkg/runtime/signal_linux_amd64.h | 32 ++ src/pkg/runtime/signal_linux_arm.c | 241 -------------- src/pkg/runtime/signal_linux_arm.h | 27 ++ src/pkg/runtime/signal_netbsd_386.c | 164 --------- src/pkg/runtime/signal_netbsd_386.h | 23 ++ src/pkg/runtime/signal_netbsd_amd64.c | 172 ---------- src/pkg/runtime/signal_netbsd_amd64.h | 31 ++ src/pkg/runtime/signal_netbsd_arm.c | 208 ------------ src/pkg/runtime/signal_netbsd_arm.h | 27 ++ src/pkg/runtime/signal_openbsd_386.c | 147 --------- src/pkg/runtime/signal_openbsd_386.h | 23 ++ src/pkg/runtime/signal_openbsd_amd64.c | 156 --------- src/pkg/runtime/signal_openbsd_amd64.h | 31 ++ src/pkg/runtime/signal_plan9_386.c | 120 ------- src/pkg/runtime/signal_plan9_amd64.c | 127 ------- src/pkg/runtime/signal_unix.c | 1 + src/pkg/runtime/signal_unix.h | 13 + src/pkg/runtime/signal_windows_386.c | 97 ------ src/pkg/runtime/signal_windows_amd64.c | 104 ------ src/pkg/runtime/thread_darwin.c | 548 ------------------------------ src/pkg/runtime/thread_freebsd.c | 259 --------------- src/pkg/runtime/thread_linux.c | 311 ----------------- src/pkg/runtime/thread_netbsd.c | 304 ----------------- src/pkg/runtime/thread_openbsd.c | 281 ---------------- src/pkg/runtime/thread_plan9.c | 344 ------------------- src/pkg/runtime/thread_windows.c | 457 ------------------------- 65 files changed, 4158 insertions(+), 5242 deletions(-) create mode 100644 src/pkg/runtime/os_darwin.c create mode 100644 src/pkg/runtime/os_freebsd.c create mode 100644 src/pkg/runtime/os_freebsd_arm.c create mode 100644 src/pkg/runtime/os_linux.c create mode 100644 src/pkg/runtime/os_linux_386.c create mode 100644 src/pkg/runtime/os_linux_arm.c create mode 100644 src/pkg/runtime/os_netbsd.c create mode 100644 src/pkg/runtime/os_netbsd_386.c create mode 100644 src/pkg/runtime/os_netbsd_amd64.c create mode 100644 src/pkg/runtime/os_netbsd_arm.c create mode 100644 src/pkg/runtime/os_openbsd.c create mode 100644 src/pkg/runtime/os_plan9.c create mode 100644 src/pkg/runtime/os_plan9_386.c create mode 100644 src/pkg/runtime/os_plan9_amd64.c create mode 100644 src/pkg/runtime/os_windows.c create mode 100644 src/pkg/runtime/os_windows_386.c create mode 100644 src/pkg/runtime/os_windows_amd64.c create mode 100644 src/pkg/runtime/signal_386.c create mode 100644 src/pkg/runtime/signal_amd64.c create mode 100644 src/pkg/runtime/signal_arm.c delete mode 100644 src/pkg/runtime/signal_darwin_386.c create mode 100644 src/pkg/runtime/signal_darwin_386.h delete mode 100644 src/pkg/runtime/signal_darwin_amd64.c create mode 100644 src/pkg/runtime/signal_darwin_amd64.h delete mode 100644 src/pkg/runtime/signal_freebsd_386.c create mode 100644 src/pkg/runtime/signal_freebsd_386.h delete mode 100644 src/pkg/runtime/signal_freebsd_amd64.c create mode 100644 src/pkg/runtime/signal_freebsd_amd64.h delete mode 100644 src/pkg/runtime/signal_freebsd_arm.c create mode 100644 src/pkg/runtime/signal_freebsd_arm.h delete mode 100644 src/pkg/runtime/signal_linux_386.c create mode 100644 src/pkg/runtime/signal_linux_386.h delete mode 100644 src/pkg/runtime/signal_linux_amd64.c create mode 100644 src/pkg/runtime/signal_linux_amd64.h delete mode 100644 src/pkg/runtime/signal_linux_arm.c create mode 100644 src/pkg/runtime/signal_linux_arm.h delete mode 100644 src/pkg/runtime/signal_netbsd_386.c create mode 100644 src/pkg/runtime/signal_netbsd_386.h delete mode 100644 src/pkg/runtime/signal_netbsd_amd64.c create mode 100644 src/pkg/runtime/signal_netbsd_amd64.h delete mode 100644 src/pkg/runtime/signal_netbsd_arm.c create mode 100644 src/pkg/runtime/signal_netbsd_arm.h delete mode 100644 src/pkg/runtime/signal_openbsd_386.c create mode 100644 src/pkg/runtime/signal_openbsd_386.h delete mode 100644 src/pkg/runtime/signal_openbsd_amd64.c create mode 100644 src/pkg/runtime/signal_openbsd_amd64.h delete mode 100644 src/pkg/runtime/signal_plan9_386.c delete mode 100644 src/pkg/runtime/signal_plan9_amd64.c create mode 100644 src/pkg/runtime/signal_unix.h delete mode 100644 src/pkg/runtime/signal_windows_386.c delete mode 100644 src/pkg/runtime/signal_windows_amd64.c delete mode 100644 src/pkg/runtime/thread_darwin.c delete mode 100644 src/pkg/runtime/thread_freebsd.c delete mode 100644 src/pkg/runtime/thread_linux.c delete mode 100644 src/pkg/runtime/thread_netbsd.c delete mode 100644 src/pkg/runtime/thread_openbsd.c delete mode 100644 src/pkg/runtime/thread_plan9.c delete mode 100644 src/pkg/runtime/thread_windows.c (limited to 'src/pkg/runtime') diff --git a/src/pkg/runtime/os_darwin.c b/src/pkg/runtime/os_darwin.c new file mode 100644 index 0000000000..ba4e6ebdfc --- /dev/null +++ b/src/pkg/runtime/os_darwin.c @@ -0,0 +1,587 @@ +// 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_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "signal_unix.h" +#include "stack.h" + +extern SigTab runtime·sigtab[]; + +static Sigset sigset_none; +static Sigset sigset_all = ~(Sigset)0; +static Sigset sigset_prof = 1<<(SIGPROF-1); + +static void +unimplemented(int8 *name) +{ + runtime·prints(name); + runtime·prints(" not implemented\n"); + *(int32*)1231 = 1231; +} + +int32 +runtime·semasleep(int64 ns) +{ + int32 v; + + if(m->profilehz > 0) + runtime·setprof(false); + v = runtime·mach_semacquire(m->waitsema, ns); + if(m->profilehz > 0) + runtime·setprof(true); + return v; +} + +void +runtime·semawakeup(M *mp) +{ + runtime·mach_semrelease(mp->waitsema); +} + +uintptr +runtime·semacreate(void) +{ + return runtime·mach_semcreate(); +} + +// BSD interface for threading. +void +runtime·osinit(void) +{ + // bsdthread_register delayed until end of goenvs so that we + // can look at the environment first. + + // Use sysctl to fetch hw.ncpu. + uint32 mib[2]; + uint32 out; + int32 ret; + uintptr nout; + + mib[0] = 6; + mib[1] = 3; + nout = sizeof out; + out = 0; + ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0); + if(ret >= 0) + runtime·ncpu = out; +} + +void +runtime·get_random_data(byte **rnd, int32 *rnd_len) +{ + static byte urandom_data[HashRandomBytes]; + int32 fd; + fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0); + if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) { + *rnd = urandom_data; + *rnd_len = HashRandomBytes; + } else { + *rnd = nil; + *rnd_len = 0; + } + runtime·close(fd); +} + +void +runtime·goenvs(void) +{ + runtime·goenvs_unix(); + + // Register our thread-creation callback (see sys_darwin_{amd64,386}.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) { + if(runtime·bsdthread_register() != 0) { + if(runtime·getenv("DYLD_INSERT_LIBRARIES")) + runtime·throw("runtime: bsdthread_register error (unset DYLD_INSERT_LIBRARIES)"); + runtime·throw("runtime: bsdthread_register error"); + } + } + +} + +void +runtime·newosproc(M *mp, void *stk) +{ + int32 errno; + Sigset oset; + + mp->tls[0] = mp->id; // so 386 asm can find it + if(0){ + runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n", + stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp); + } + + runtime·sigprocmask(SIG_SETMASK, &sigset_all, &oset); + errno = runtime·bsdthread_create(stk, mp, mp->g0, runtime·mstart); + runtime·sigprocmask(SIG_SETMASK, &oset, nil); + + if(errno < 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). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +void +runtime·mpreinit(M *mp) +{ + mp->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +void +runtime·minit(void) +{ + // Initialize signal handling. + runtime·signalstack((byte*)m->gsignal->stackguard - StackGuard, 32*1024); + + runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); + runtime·setprof(m->profilehz > 0); +} + +// Called from dropm to undo the effect of an minit. +void +runtime·unminit(void) +{ + runtime·signalstack(nil, 0); +} + +// 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; imsgh_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; imsgh_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, + KERN_OPERATION_TIMED_OUT = 49, +}; + +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_darwin_{amd64,386}.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); + +int32 +runtime·mach_semacquire(uint32 sem, int64 ns) +{ + int32 r; + + if(ns >= 0) { + r = runtime·mach_semaphore_timedwait(sem, ns/1000000000LL, ns%1000000000LL); + if(r == KERN_ABORTED || r == KERN_OPERATION_TIMED_OUT) + return -1; + if(r != 0) + macherror(r, "semaphore_wait"); + return 0; + } + while((r = runtime·mach_semaphore_wait(sem)) != 0) { + if(r == KERN_ABORTED) // interrupted + continue; + macherror(r, "semaphore_wait"); + } + return 0; +} + +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) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); + 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) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); + 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); +} + +#pragma textflag 7 +void +runtime·osyield(void) +{ + runtime·usleep(1); +} + +uintptr +runtime·memlimit(void) +{ + // NOTE(rsc): Could use getrlimit here, + // like on FreeBSD or Linux, but Darwin doesn't enforce + // ulimit -v, so it's unclear why we'd try to stay within + // the limit. + return 0; +} + +// NOTE(rsc): On OS X, when the CPU profiling timer expires, the SIGPROF +// signal is not guaranteed to be sent to the thread that was executing to +// cause it to expire. It can and often does go to a sleeping thread, which is +// not interesting for our profile. This is filed Apple Bug Report #9177434, +// copied to http://code.google.com/p/go/source/detail?r=35b716c94225. +// To work around this bug, we disable receipt of the profiling signal on +// a thread while in blocking system calls. This forces the kernel to deliver +// the profiling signal to an executing thread. +// +// The workaround fails on OS X machines using a 64-bit Snow Leopard kernel. +// In that configuration, the kernel appears to want to deliver SIGPROF to the +// sleeping threads regardless of signal mask and, worse, does not deliver +// the signal until the thread wakes up on its own. +// +// If necessary, we can switch to using ITIMER_REAL for OS X and handle +// the kernel-generated SIGALRM by generating our own SIGALRMs to deliver +// to all the running threads. SIGALRM does not appear to be affected by +// the 64-bit Snow Leopard bug. However, as of this writing Mountain Lion +// is in preview, making Snow Leopard two versions old, so it is unclear how +// much effort we need to spend on one buggy kernel. + +// Control whether profiling signal can be delivered to this thread. +void +runtime·setprof(bool on) +{ + if(on) + runtime·sigprocmask(SIG_UNBLOCK, &sigset_prof, nil); + else + runtime·sigprocmask(SIG_BLOCK, &sigset_prof, nil); +} + +static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n"; + +// This runs on a foreign stack, without an m or a g. No stack split. +#pragma textflag 7 +void +runtime·badcallback(void) +{ + runtime·write(2, badcallback, sizeof badcallback - 1); +} + +static int8 badsignal[] = "runtime: signal received on thread not created by Go: "; + +// This runs on a foreign stack, without an m or a g. No stack split. +#pragma textflag 7 +void +runtime·badsignal(int32 sig) +{ + if (sig == SIGPROF) { + return; // Ignore SIGPROFs intended for a non-Go thread. + } + runtime·write(2, badsignal, sizeof badsignal - 1); + if (0 <= sig && sig < NSIG) { + // Call runtime·findnull dynamically to circumvent static stack size check. + static int32 (*findnull)(byte*) = runtime·findnull; + runtime·write(2, runtime·sigtab[sig].name, findnull((byte*)runtime·sigtab[sig].name)); + } + runtime·write(2, "\n", 1); + runtime·exit(1); +} + +void +runtime·setsig(int32 i, GoSighandler *fn, 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 = ~(uintptr)0; + sa.sa_tramp = (void*)runtime·sigtramp; // runtime·sigtramp's job is to call into real handler + *(uintptr*)sa.__sigaction_u = (uintptr)fn; + runtime·sigaction(i, &sa, nil); +} + +GoSighandler* +runtime·getsig(int32 i) +{ + Sigaction sa; + + runtime·memclr((byte*)&sa, sizeof sa); + runtime·sigaction(i, nil, &sa); + return *(void**)sa.__sigaction_u; +} + +void +runtime·signalstack(byte *p, int32 n) +{ + StackT st; + + st.ss_sp = (void*)p; + st.ss_size = n; + st.ss_flags = 0; + if(p == nil) + st.ss_flags = SS_DISABLE; + runtime·sigaltstack(&st, nil); +} diff --git a/src/pkg/runtime/os_darwin.h b/src/pkg/runtime/os_darwin.h index 5fcb717cbb..8024109753 100644 --- a/src/pkg/runtime/os_darwin.h +++ b/src/pkg/runtime/os_darwin.h @@ -2,9 +2,6 @@ // 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) -#define SIGHUP 1 #define SS_DISABLE 4 int32 runtime·bsdthread_create(void*, M*, G*, void(*)(void)); @@ -27,8 +24,6 @@ void runtime·sigprocmask(int32, Sigset*, Sigset*); struct Sigaction; void runtime·sigaction(uintptr, struct Sigaction*, struct Sigaction*); -void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool); -void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp); struct StackT; void runtime·sigaltstack(struct StackT*, struct StackT*); @@ -36,7 +31,6 @@ void runtime·sigtramp(void); void runtime·sigpanic(void); void runtime·setitimer(int32, Itimerval*, Itimerval*); -void runtime·raisesigpipe(void); #define NSIG 32 #define SI_USER 0 /* empirically true, but not what headers say */ diff --git a/src/pkg/runtime/os_freebsd.c b/src/pkg/runtime/os_freebsd.c new file mode 100644 index 0000000000..0632eabd30 --- /dev/null +++ b/src/pkg/runtime/os_freebsd.c @@ -0,0 +1,315 @@ +// Use of this source file is governed by a BSD-style +// license that can be found in the LICENSE file.` + +#include "runtime.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "signal_unix.h" +#include "stack.h" + +extern SigTab runtime·sigtab[]; +extern int32 runtime·sys_umtx_op(uint32*, int32, uint32, void*, void*); + +// From FreeBSD's +#define CTL_HW 6 +#define HW_NCPU 3 + +static Sigset sigset_none; +static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, }; + +static int32 +getncpu(void) +{ + uint32 mib[2]; + uint32 out; + int32 ret; + uintptr nout; + + // Fetch hw.ncpu via sysctl. + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + nout = sizeof out; + out = 0; + ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0); + if(ret >= 0) + return out; + else + return 1; +} + +// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and +// thus the code is largely similar. See linux/thread.c and lock_futex.c for comments. + +void +runtime·futexsleep(uint32 *addr, uint32 val, int64 ns) +{ + int32 ret; + Timespec ts, *tsp; + + if(ns < 0) + tsp = nil; + else { + ts.tv_sec = ns / 1000000000LL; + ts.tv_nsec = ns % 1000000000LL; + tsp = &ts; + } + + ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT, val, nil, tsp); + if(ret >= 0 || ret == -EINTR) + return; + + runtime·printf("umtx_wait addr=%p val=%d ret=%d\n", addr, val, ret); + *(int32*)0x1005 = 0x1005; +} + +void +runtime·futexwakeup(uint32 *addr, uint32 cnt) +{ + int32 ret; + + ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE, cnt, nil, nil); + if(ret >= 0) + return; + + runtime·printf("umtx_wake addr=%p ret=%d\n", addr, ret); + *(int32*)0x1006 = 0x1006; +} + +void runtime·thr_start(void*); + +void +runtime·newosproc(M *mp, void *stk) +{ + ThrParam param; + Sigset oset; + + if(0){ + runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n", + stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp); + } + + runtime·sigprocmask(&sigset_all, &oset); + runtime·memclr((byte*)¶m, sizeof param); + + param.start_func = runtime·thr_start; + param.arg = (byte*)mp; + + // NOTE(rsc): This code is confused. stackbase is the top of the stack + // and is equal to stk. However, it's working, so I'm not changing it. + param.stack_base = (void*)mp->g0->stackbase; + param.stack_size = (byte*)stk - (byte*)mp->g0->stackbase; + + param.child_tid = (intptr*)&mp->procid; + param.parent_tid = nil; + param.tls_base = (void*)&mp->tls[0]; + param.tls_size = sizeof mp->tls; + + mp->tls[0] = mp->id; // so 386 asm can find it + + runtime·thr_new(¶m, sizeof param); + runtime·sigprocmask(&oset, nil); +} + +void +runtime·osinit(void) +{ + runtime·ncpu = getncpu(); +} + +void +runtime·get_random_data(byte **rnd, int32 *rnd_len) +{ + static byte urandom_data[HashRandomBytes]; + int32 fd; + fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0); + if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) { + *rnd = urandom_data; + *rnd_len = HashRandomBytes; + } else { + *rnd = nil; + *rnd_len = 0; + } + runtime·close(fd); +} + +void +runtime·goenvs(void) +{ + runtime·goenvs_unix(); +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +void +runtime·mpreinit(M *mp) +{ + mp->gsignal = runtime·malg(32*1024); +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +void +runtime·minit(void) +{ + // Initialize signal handling + runtime·signalstack((byte*)m->gsignal->stackguard - StackGuard, 32*1024); + runtime·sigprocmask(&sigset_none, nil); +} + +// Called from dropm to undo the effect of an minit. +void +runtime·unminit(void) +{ + runtime·signalstack(nil, 0); +} + +void +runtime·sigpanic(void) +{ + switch(g->sig) { + case SIGBUS: + if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); + 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) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); + 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); +} + +uintptr +runtime·memlimit(void) +{ + Rlimit rl; + extern byte text[], end[]; + uintptr used; + + if(runtime·getrlimit(RLIMIT_AS, &rl) != 0) + return 0; + if(rl.rlim_cur >= 0x7fffffff) + return 0; + + // Estimate our VM footprint excluding the heap. + // Not an exact science: use size of binary plus + // some room for thread stacks. + used = end - text + (64<<20); + if(used >= rl.rlim_cur) + return 0; + + // If there's not at least 16 MB left, we're probably + // not going to be able to do much. Treat as no limit. + rl.rlim_cur -= used; + if(rl.rlim_cur < (16<<20)) + return 0; + + return rl.rlim_cur - used; +} + +void +runtime·setprof(bool on) +{ + USED(on); +} + +static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n"; + +// This runs on a foreign stack, without an m or a g. No stack split. +#pragma textflag 7 +void +runtime·badcallback(void) +{ + runtime·write(2, badcallback, sizeof badcallback - 1); +} + +static int8 badsignal[] = "runtime: signal received on thread not created by Go: "; + +// This runs on a foreign stack, without an m or a g. No stack split. +#pragma textflag 7 +void +runtime·badsignal(int32 sig) +{ + if (sig == SIGPROF) { + return; // Ignore SIGPROFs intended for a non-Go thread. + } + runtime·write(2, badsignal, sizeof badsignal - 1); + if (0 <= sig && sig < NSIG) { + // Call runtime·findnull dynamically to circumvent static stack size check. + static int32 (*findnull)(byte*) = runtime·findnull; + runtime·write(2, runtime·sigtab[sig].name, findnull((byte*)runtime·sigtab[sig].name)); + } + runtime·write(2, "\n", 1); + runtime·exit(1); +} + +extern void runtime·sigtramp(void); + +typedef struct sigaction { + union { + void (*__sa_handler)(int32); + void (*__sa_sigaction)(int32, Siginfo*, void *); + } __sigaction_u; /* signal handler */ + int32 sa_flags; /* see signal options below */ + Sigset sa_mask; /* signal mask to apply */ +} Sigaction; + +void +runtime·setsig(int32 i, GoSighandler *fn, 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.__bits[0] = ~(uint32)0; + sa.sa_mask.__bits[1] = ~(uint32)0; + sa.sa_mask.__bits[2] = ~(uint32)0; + sa.sa_mask.__bits[3] = ~(uint32)0; + if(fn == runtime·sighandler) + fn = (void*)runtime·sigtramp; + sa.__sigaction_u.__sa_sigaction = (void*)fn; + runtime·sigaction(i, &sa, nil); +} + +GoSighandler* +runtime·getsig(int32 i) +{ + Sigaction sa; + + runtime·memclr((byte*)&sa, sizeof sa); + runtime·sigaction(i, nil, &sa); + if((void*)sa.__sigaction_u.__sa_sigaction == runtime·sigtramp) + return runtime·sighandler; + return (void*)sa.__sigaction_u.__sa_sigaction; +} + +void +runtime·signalstack(byte *p, int32 n) +{ + StackT st; + + st.ss_sp = (void*)p; + st.ss_size = n; + st.ss_flags = 0; + if(p == nil) + st.ss_flags = SS_DISABLE; + runtime·sigaltstack(&st, nil); +} diff --git a/src/pkg/runtime/os_freebsd.h b/src/pkg/runtime/os_freebsd.h index a37ad7cd87..3d631bfc80 100644 --- a/src/pkg/runtime/os_freebsd.h +++ b/src/pkg/runtime/os_freebsd.h @@ -1,20 +1,14 @@ -#define SIG_DFL ((void*)0) -#define SIG_IGN ((void*)1) -#define SIGHUP 1 #define SS_DISABLE 4 int32 runtime·thr_new(ThrParam*, int32); -void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp); void runtime·sigpanic(void); void runtime·sigaltstack(Sigaltstack*, Sigaltstack*); struct sigaction; void runtime·sigaction(int32, struct sigaction*, struct sigaction*); void runtime·sigprocmask(Sigset *, Sigset *); -void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool); void runtime·setitimer(int32, Itimerval*, Itimerval*); int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr); -void runtime·raisesigpipe(void); #define NSIG 33 #define SI_USER 0x10001 diff --git a/src/pkg/runtime/os_freebsd_arm.c b/src/pkg/runtime/os_freebsd_arm.c new file mode 100644 index 0000000000..7eaa45c441 --- /dev/null +++ b/src/pkg/runtime/os_freebsd_arm.c @@ -0,0 +1,23 @@ +// Copyright 2012 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_GOOS_GOARCH.h" +#include "os_GOOS.h" + +void +runtime·checkgoarm(void) +{ + // TODO(minux) +} + +#pragma textflag 7 +int64 +runtime·cputicks(void) +{ + // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1(). + // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler. + // TODO: need more entropy to better seed fastrand1. + return runtime·nanotime(); +} diff --git a/src/pkg/runtime/os_linux.c b/src/pkg/runtime/os_linux.c new file mode 100644 index 0000000000..dc1e274378 --- /dev/null +++ b/src/pkg/runtime/os_linux.c @@ -0,0 +1,369 @@ +// 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_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "signal_unix.h" +#include "stack.h" + +extern SigTab runtime·sigtab[]; + +static Sigset sigset_none; +static Sigset sigset_all = { ~(uint32)0, ~(uint32)0 }; + +// Linux futex. +// +// futexsleep(uint32 *addr, uint32 val) +// futexwakeup(uint32 *addr) +// +// Futexsleep atomically checks if *addr == val and if so, sleeps on addr. +// Futexwakeup wakes up threads sleeping on addr. +// Futexsleep is allowed to wake up spuriously. + +enum +{ + FUTEX_WAIT = 0, + FUTEX_WAKE = 1, +}; + +// Atomically, +// if(*addr == val) sleep +// Might be woken up spuriously; that's allowed. +// Don't sleep longer than ns; ns < 0 means forever. +void +runtime·futexsleep(uint32 *addr, uint32 val, int64 ns) +{ + Timespec ts, *tsp; + + if(ns < 0) + tsp = nil; + else { + ts.tv_sec = ns/1000000000LL; + ts.tv_nsec = ns%1000000000LL; + // Avoid overflow + if(ts.tv_sec > 1<<30) + ts.tv_sec = 1<<30; + tsp = &ts; + } + + // Some Linux kernels have a bug where futex of + // FUTEX_WAIT returns an internal error code + // as an errno. Libpthread ignores the return value + // here, and so can we: as it says a few lines up, + // spurious wakeups are allowed. + runtime·futex(addr, FUTEX_WAIT, val, tsp, nil, 0); +} + +// If any procs are sleeping on addr, wake up at most cnt. +void +runtime·futexwakeup(uint32 *addr, uint32 cnt) +{ + int64 ret; + + ret = runtime·futex(addr, FUTEX_WAKE, cnt, nil, nil, 0); + + if(ret >= 0) + return; + + // I don't know that futex wakeup can return + // EAGAIN or EINTR, but if it does, it would be + // safe to loop and call futex again. + runtime·printf("futexwakeup addr=%p returned %D\n", addr, ret); + *(int32*)0x1006 = 0x1006; +} + +extern runtime·sched_getaffinity(uintptr pid, uintptr len, uintptr *buf); +static int32 +getproccount(void) +{ + uintptr buf[16], t; + int32 r, cnt, i; + + cnt = 0; + r = runtime·sched_getaffinity(0, sizeof(buf), buf); + if(r > 0) + for(i = 0; i < r/sizeof(buf[0]); i++) { + t = buf[i]; + t = t - ((t >> 1) & 0x5555555555555555ULL); + t = (t & 0x3333333333333333ULL) + ((t >> 2) & 0x3333333333333333ULL); + cnt += (int32)((((t + (t >> 4)) & 0xF0F0F0F0F0F0F0FULL) * 0x101010101010101ULL) >> 56); + } + + return cnt ? cnt : 1; +} + +// Clone, the Linux rfork. +enum +{ + CLONE_VM = 0x100, + CLONE_FS = 0x200, + CLONE_FILES = 0x400, + CLONE_SIGHAND = 0x800, + CLONE_PTRACE = 0x2000, + CLONE_VFORK = 0x4000, + CLONE_PARENT = 0x8000, + CLONE_THREAD = 0x10000, + CLONE_NEWNS = 0x20000, + CLONE_SYSVSEM = 0x40000, + CLONE_SETTLS = 0x80000, + CLONE_PARENT_SETTID = 0x100000, + CLONE_CHILD_CLEARTID = 0x200000, + CLONE_UNTRACED = 0x800000, + CLONE_CHILD_SETTID = 0x1000000, + CLONE_STOPPED = 0x2000000, + CLONE_NEWUTS = 0x4000000, + CLONE_NEWIPC = 0x8000000, +}; + +void +runtime·newosproc(M *mp, void *stk) +{ + int32 ret; + int32 flags; + Sigset oset; + + /* + * note: strace gets confused if we use CLONE_PTRACE here. + */ + flags = CLONE_VM /* share memory */ + | CLONE_FS /* share cwd, etc */ + | CLONE_FILES /* share fd table */ + | CLONE_SIGHAND /* share sig handler table */ + | CLONE_THREAD /* revisit - okay for now */ + ; + + mp->tls[0] = mp->id; // so 386 asm can find it + if(0){ + runtime·printf("newosproc stk=%p m=%p g=%p clone=%p id=%d/%d ostk=%p\n", + stk, mp, mp->g0, runtime·clone, mp->id, (int32)mp->tls[0], &mp); + } + + // Disable signals during clone, so that the new thread starts + // with signals disabled. It will enable them in minit. + runtime·rtsigprocmask(SIG_SETMASK, &sigset_all, &oset, sizeof oset); + ret = runtime·clone(flags, stk, mp, mp->g0, runtime·mstart); + runtime·rtsigprocmask(SIG_SETMASK, &oset, nil, sizeof oset); + + if(ret < 0) { + runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), -ret); + runtime·throw("runtime.newosproc"); + } +} + +void +runtime·osinit(void) +{ + runtime·ncpu = getproccount(); +} + +// Random bytes initialized at startup. These come +// from the ELF AT_RANDOM auxiliary vector (vdso_linux_amd64.c). +byte* runtime·startup_random_data; +uint32 runtime·startup_random_data_len; + +void +runtime·get_random_data(byte **rnd, int32 *rnd_len) +{ + if(runtime·startup_random_data != nil) { + *rnd = runtime·startup_random_data; + *rnd_len = runtime·startup_random_data_len; + } else { + static byte urandom_data[HashRandomBytes]; + int32 fd; + fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0); + if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) { + *rnd = urandom_data; + *rnd_len = HashRandomBytes; + } else { + *rnd = nil; + *rnd_len = 0; + } + runtime·close(fd); + } +} + +void +runtime·goenvs(void) +{ + runtime·goenvs_unix(); +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +void +runtime·mpreinit(M *mp) +{ + mp->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +void +runtime·minit(void) +{ + // Initialize signal handling. + runtime·signalstack((byte*)m->gsignal->stackguard - StackGuard, 32*1024); + runtime·rtsigprocmask(SIG_SETMASK, &sigset_none, nil, sizeof(Sigset)); +} + +// Called from dropm to undo the effect of an minit. +void +runtime·unminit(void) +{ + runtime·signalstack(nil, 0); +} + +void +runtime·sigpanic(void) +{ + switch(g->sig) { + case SIGBUS: + if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); + } + 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) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); + 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); +} + +uintptr +runtime·memlimit(void) +{ + Rlimit rl; + extern byte text[], end[]; + uintptr used; + + if(runtime·getrlimit(RLIMIT_AS, &rl) != 0) + return 0; + if(rl.rlim_cur >= 0x7fffffff) + return 0; + + // Estimate our VM footprint excluding the heap. + // Not an exact science: use size of binary plus + // some room for thread stacks. + used = end - text + (64<<20); + if(used >= rl.rlim_cur) + return 0; + + // If there's not at least 16 MB left, we're probably + // not going to be able to do much. Treat as no limit. + rl.rlim_cur -= used; + if(rl.rlim_cur < (16<<20)) + return 0; + + return rl.rlim_cur - used; +} + +void +runtime·setprof(bool on) +{ + USED(on); +} + +static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n"; + +// This runs on a foreign stack, without an m or a g. No stack split. +#pragma textflag 7 +void +runtime·badcallback(void) +{ + runtime·write(2, badcallback, sizeof badcallback - 1); +} + +static int8 badsignal[] = "runtime: signal received on thread not created by Go: "; + +// This runs on a foreign stack, without an m or a g. No stack split. +#pragma textflag 7 +void +runtime·badsignal(int32 sig) +{ + if (sig == SIGPROF) { + return; // Ignore SIGPROFs intended for a non-Go thread. + } + runtime·write(2, badsignal, sizeof badsignal - 1); + if (0 <= sig && sig < NSIG) { + // Call runtime·findnull dynamically to circumvent static stack size check. + static int32 (*findnull)(byte*) = runtime·findnull; + runtime·write(2, runtime·sigtab[sig].name, findnull((byte*)runtime·sigtab[sig].name)); + } + runtime·write(2, "\n", 1); + runtime·exit(1); +} + +#ifdef GOARCH_386 +#define sa_handler k_sa_handler +#endif + +/* + * This assembler routine takes the args from registers, puts them on the stack, + * and calls sighandler(). + */ +extern void runtime·sigtramp(void); +extern void runtime·sigreturn(void); // calls runtime·sigreturn + +void +runtime·setsig(int32 i, GoSighandler *fn, bool restart) +{ + Sigaction sa; + + runtime·memclr((byte*)&sa, sizeof sa); + sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER; + if(restart) + sa.sa_flags |= SA_RESTART; + sa.sa_mask = ~0ULL; + // TODO(adonovan): Linux manpage says "sa_restorer element is + // obsolete and should not be used". Avoid it here, and test. + sa.sa_restorer = (void*)runtime·sigreturn; + if(fn == runtime·sighandler) + fn = (void*)runtime·sigtramp; + sa.sa_handler = fn; + if(runtime·rt_sigaction(i, &sa, nil, sizeof(sa.sa_mask)) != 0) + runtime·throw("rt_sigaction failure"); +} + +GoSighandler* +runtime·getsig(int32 i) +{ + Sigaction sa; + + runtime·memclr((byte*)&sa, sizeof sa); + if(runtime·rt_sigaction(i, nil, &sa, sizeof(sa.sa_mask)) != 0) + runtime·throw("rt_sigaction read failure"); + if((void*)sa.sa_handler == runtime·sigtramp) + return runtime·sighandler; + return (void*)sa.sa_handler; +} + +void +runtime·signalstack(byte *p, int32 n) +{ + Sigaltstack st; + + st.ss_sp = p; + st.ss_size = n; + st.ss_flags = 0; + if(p == nil) + st.ss_flags = SS_DISABLE; + runtime·sigaltstack(&st, nil); +} diff --git a/src/pkg/runtime/os_linux.h b/src/pkg/runtime/os_linux.h index a23fe0f735..b2d3f6f2aa 100644 --- a/src/pkg/runtime/os_linux.h +++ b/src/pkg/runtime/os_linux.h @@ -2,9 +2,6 @@ // 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) -#define SIGHUP 1 #define SS_DISABLE 2 // Linux-specific system calls @@ -13,14 +10,11 @@ int32 runtime·clone(int32, void*, M*, G*, void(*)(void)); struct Sigaction; int32 runtime·rt_sigaction(uintptr, struct Sigaction*, void*, uintptr); -void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool); -void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp); void runtime·sigaltstack(Sigaltstack*, Sigaltstack*); void runtime·sigpanic(void); void runtime·setitimer(int32, Itimerval*, Itimerval*); -void runtime·raisesigpipe(void); #define NSIG 65 #define SI_USER 0 diff --git a/src/pkg/runtime/os_linux_386.c b/src/pkg/runtime/os_linux_386.c new file mode 100644 index 0000000000..18becb6e65 --- /dev/null +++ b/src/pkg/runtime/os_linux_386.c @@ -0,0 +1,37 @@ +// 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_GOOS_GOARCH.h" +#include "os_GOOS.h" + +#define AT_NULL 0 +#define AT_RANDOM 25 +#define AT_SYSINFO 32 +extern uint32 runtime·_vdso; + +#pragma textflag 7 +void +runtime·linux_setup_vdso(int32 argc, byte **argv) +{ + byte **envp; + uint32 *auxv; + + // skip envp to get to ELF auxiliary vector. + for(envp = &argv[argc+1]; *envp != nil; envp++) + ; + envp++; + + for(auxv=(uint32*)envp; auxv[0] != AT_NULL; auxv += 2) { + if(auxv[0] == AT_SYSINFO) { + runtime·_vdso = auxv[1]; + continue; + } + if(auxv[0] == AT_RANDOM) { + runtime·startup_random_data = (byte*)auxv[1]; + runtime·startup_random_data_len = 16; + continue; + } + } +} diff --git a/src/pkg/runtime/os_linux_arm.c b/src/pkg/runtime/os_linux_arm.c new file mode 100644 index 0000000000..dd0fa94154 --- /dev/null +++ b/src/pkg/runtime/os_linux_arm.c @@ -0,0 +1,82 @@ +// 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_GOOS_GOARCH.h" +#include "os_GOOS.h" + +#define AT_NULL 0 +#define AT_PLATFORM 15 // introduced in at least 2.6.11 +#define AT_HWCAP 16 // introduced in at least 2.6.11 +#define AT_RANDOM 25 // introduced in 2.6.29 +#define HWCAP_VFP (1 << 6) // introduced in at least 2.6.11 +#define HWCAP_VFPv3 (1 << 13) // introduced in 2.6.30 +static uint32 runtime·randomNumber; +uint8 runtime·armArch = 6; // we default to ARMv6 +uint32 runtime·hwcap; // set by setup_auxv +uint8 runtime·goarm; // set by 5l + +void +runtime·checkgoarm(void) +{ + if(runtime·goarm > 5 && !(runtime·hwcap & HWCAP_VFP)) { + runtime·printf("runtime: this CPU has no floating point hardware, so it cannot run\n"); + runtime·printf("this GOARM=%d binary. Recompile using GOARM=5.\n", runtime·goarm); + runtime·exit(1); + } + if(runtime·goarm > 6 && !(runtime·hwcap & HWCAP_VFPv3)) { + runtime·printf("runtime: this CPU has no VFPv3 floating point hardware, so it cannot run\n"); + runtime·printf("this GOARM=%d binary. Recompile using GOARM=6.\n", runtime·goarm); + runtime·exit(1); + } +} + +#pragma textflag 7 +void +runtime·setup_auxv(int32 argc, void *argv_list) +{ + byte **argv; + byte **envp; + byte *rnd; + uint32 *auxv; + uint32 t; + + argv = &argv_list; + + // skip envp to get to ELF auxiliary vector. + for(envp = &argv[argc+1]; *envp != nil; envp++) + ; + envp++; + + for(auxv=(uint32*)envp; auxv[0] != AT_NULL; auxv += 2) { + switch(auxv[0]) { + case AT_RANDOM: // kernel provided 16-byte worth of random data + if(auxv[1]) { + rnd = (byte*)auxv[1]; + runtime·randomNumber = rnd[4] | rnd[5]<<8 | rnd[6]<<16 | rnd[7]<<24; + } + break; + case AT_PLATFORM: // v5l, v6l, v7l + if(auxv[1]) { + t = *(uint8*)(auxv[1]+1); + if(t >= '5' && t <= '7') + runtime·armArch = t - '0'; + } + break; + case AT_HWCAP: // CPU capability bit flags + runtime·hwcap = auxv[1]; + break; + } + } +} + +#pragma textflag 7 +int64 +runtime·cputicks(void) +{ + // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1(). + // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler. + // runtime·randomNumber provides better seeding of fastrand1. + return runtime·nanotime() + runtime·randomNumber; +} diff --git a/src/pkg/runtime/os_netbsd.c b/src/pkg/runtime/os_netbsd.c new file mode 100644 index 0000000000..d4b874f4c2 --- /dev/null +++ b/src/pkg/runtime/os_netbsd.c @@ -0,0 +1,360 @@ +// Use of this source file is governed by a BSD-style +// license that can be found in the LICENSE file.` + +#include "runtime.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "signal_unix.h" +#include "stack.h" + +enum +{ + ESRCH = 3, + ENOTSUP = 91, + + // From NetBSD's + CLOCK_REALTIME = 0, + CLOCK_VIRTUAL = 1, + CLOCK_PROF = 2, + CLOCK_MONOTONIC = 3 +}; + +extern SigTab runtime·sigtab[]; + +static Sigset sigset_none; +static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, }; + +extern void runtime·getcontext(UcontextT *context); +extern int32 runtime·lwp_create(UcontextT *context, uintptr flags, void *lwpid); +extern void runtime·lwp_mcontext_init(void *mc, void *stack, M *mp, G *gp, void (*fn)(void)); +extern int32 runtime·lwp_park(Timespec *abstime, int32 unpark, void *hint, void *unparkhint); +extern int32 runtime·lwp_unpark(int32 lwp, void *hint); +extern int32 runtime·lwp_self(void); + +// From NetBSD's +#define CTL_HW 6 +#define HW_NCPU 3 + +static int32 +getncpu(void) +{ + uint32 mib[2]; + uint32 out; + int32 ret; + uintptr nout; + + // Fetch hw.ncpu via sysctl. + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + nout = sizeof out; + out = 0; + ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0); + if(ret >= 0) + return out; + else + return 1; +} + +uintptr +runtime·semacreate(void) +{ + return 1; +} + +int32 +runtime·semasleep(int64 ns) +{ + Timespec ts; + + // spin-mutex lock + while(runtime·xchg(&m->waitsemalock, 1)) + runtime·osyield(); + + for(;;) { + // lock held + if(m->waitsemacount == 0) { + // sleep until semaphore != 0 or timeout. + // thrsleep unlocks m->waitsemalock. + if(ns < 0) { + // TODO(jsing) - potential deadlock! + // + // There is a potential deadlock here since we + // have to release the waitsemalock mutex + // before we call lwp_park() to suspend the + // thread. This allows another thread to + // release the lock and call lwp_unpark() + // before the thread is actually suspended. + // If this occurs the current thread will end + // up sleeping indefinitely. Unfortunately + // the NetBSD kernel does not appear to provide + // a mechanism for unlocking the userspace + // mutex once the thread is actually parked. + runtime·atomicstore(&m->waitsemalock, 0); + runtime·lwp_park(nil, 0, &m->waitsemacount, nil); + } else { + ns += runtime·nanotime(); + ts.tv_sec = ns/1000000000LL; + ts.tv_nsec = ns%1000000000LL; + // TODO(jsing) - potential deadlock! + // See above for details. + runtime·atomicstore(&m->waitsemalock, 0); + runtime·lwp_park(&ts, 0, &m->waitsemacount, nil); + } + // reacquire lock + while(runtime·xchg(&m->waitsemalock, 1)) + runtime·osyield(); + } + + // lock held (again) + if(m->waitsemacount != 0) { + // semaphore is available. + m->waitsemacount--; + // spin-mutex unlock + runtime·atomicstore(&m->waitsemalock, 0); + return 0; // semaphore acquired + } + + // semaphore not available. + // if there is a timeout, stop now. + // otherwise keep trying. + if(ns >= 0) + break; + } + + // lock held but giving up + // spin-mutex unlock + runtime·atomicstore(&m->waitsemalock, 0); + return -1; +} + +void +runtime·semawakeup(M *mp) +{ + uint32 ret; + + // spin-mutex lock + while(runtime·xchg(&mp->waitsemalock, 1)) + runtime·osyield(); + mp->waitsemacount++; + // TODO(jsing) - potential deadlock, see semasleep() for details. + // Confirm that LWP is parked before unparking... + ret = runtime·lwp_unpark(mp->procid, &mp->waitsemacount); + if(ret != 0 && ret != ESRCH) + runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret); + // spin-mutex unlock + runtime·atomicstore(&mp->waitsemalock, 0); +} + +void +runtime·newosproc(M *mp, void *stk) +{ + UcontextT uc; + int32 ret; + + if(0) { + runtime·printf( + "newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n", + stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp); + } + + mp->tls[0] = mp->id; // so 386 asm can find it + + runtime·getcontext(&uc); + + uc.uc_flags = _UC_SIGMASK | _UC_CPU; + uc.uc_link = nil; + uc.uc_sigmask = sigset_all; + + runtime·lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp->g0, runtime·mstart); + + ret = runtime·lwp_create(&uc, 0, &mp->procid); + + if(ret < 0) { + runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret); + runtime·throw("runtime.newosproc"); + } +} + +void +runtime·osinit(void) +{ + runtime·ncpu = getncpu(); +} + +void +runtime·get_random_data(byte **rnd, int32 *rnd_len) +{ + static byte urandom_data[HashRandomBytes]; + int32 fd; + fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0); + if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) { + *rnd = urandom_data; + *rnd_len = HashRandomBytes; + } else { + *rnd = nil; + *rnd_len = 0; + } + runtime·close(fd); +} + +void +runtime·goenvs(void) +{ + runtime·goenvs_unix(); +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +void +runtime·mpreinit(M *mp) +{ + mp->gsignal = runtime·malg(32*1024); +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +void +runtime·minit(void) +{ + m->procid = runtime·lwp_self(); + + // Initialize signal handling + runtime·signalstack((byte*)m->gsignal->stackguard - StackGuard, 32*1024); + runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); +} + +// Called from dropm to undo the effect of an minit. +void +runtime·unminit(void) +{ + runtime·signalstack(nil, 0); +} + +void +runtime·sigpanic(void) +{ + switch(g->sig) { + case SIGBUS: + if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); + 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) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); + 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); +} + +uintptr +runtime·memlimit(void) +{ + return 0; +} + +void +runtime·setprof(bool on) +{ + USED(on); +} + +static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n"; + +// This runs on a foreign stack, without an m or a g. No stack split. +#pragma textflag 7 +void +runtime·badcallback(void) +{ + runtime·write(2, badcallback, sizeof badcallback - 1); +} + +static int8 badsignal[] = "runtime: signal received on thread not created by Go: "; + +// This runs on a foreign stack, without an m or a g. No stack split. +#pragma textflag 7 +void +runtime·badsignal(int32 sig) +{ + if (sig == SIGPROF) { + return; // Ignore SIGPROFs intended for a non-Go thread. + } + runtime·write(2, badsignal, sizeof badsignal - 1); + if (0 <= sig && sig < NSIG) { + // Call runtime·findnull dynamically to circumvent static stack size check. + static int32 (*findnull)(byte*) = runtime·findnull; + runtime·write(2, runtime·sigtab[sig].name, findnull((byte*)runtime·sigtab[sig].name)); + } + runtime·write(2, "\n", 1); + runtime·exit(1); +} + +extern void runtime·sigtramp(void); + +typedef struct sigaction { + union { + void (*_sa_handler)(int32); + void (*_sa_sigaction)(int32, Siginfo*, void *); + } _sa_u; /* signal handler */ + uint32 sa_mask[4]; /* signal mask to apply */ + int32 sa_flags; /* see signal options below */ +} Sigaction; + +void +runtime·setsig(int32 i, GoSighandler *fn, 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[0] = ~0U; + sa.sa_mask[1] = ~0U; + sa.sa_mask[2] = ~0U; + sa.sa_mask[3] = ~0U; + if (fn == runtime·sighandler) + fn = (void*)runtime·sigtramp; + sa._sa_u._sa_sigaction = (void*)fn; + runtime·sigaction(i, &sa, nil); +} + +GoSighandler* +runtime·getsig(int32 i) +{ + Sigaction sa; + + runtime·memclr((byte*)&sa, sizeof sa); + runtime·sigaction(i, nil, &sa); + if((void*)sa._sa_u._sa_sigaction == runtime·sigtramp) + return runtime·sighandler; + return (void*)sa._sa_u._sa_sigaction; +} + +void +runtime·signalstack(byte *p, int32 n) +{ + StackT st; + + st.ss_sp = (void*)p; + st.ss_size = n; + st.ss_flags = 0; + if(p == nil) + st.ss_flags = SS_DISABLE; + runtime·sigaltstack(&st, nil); +} diff --git a/src/pkg/runtime/os_netbsd.h b/src/pkg/runtime/os_netbsd.h index 19d72fd254..84e0b241d1 100644 --- a/src/pkg/runtime/os_netbsd.h +++ b/src/pkg/runtime/os_netbsd.h @@ -2,9 +2,6 @@ // 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) -#define SIGHUP 1 #define SS_DISABLE 4 #define SIG_BLOCK 1 @@ -13,9 +10,6 @@ struct sigaction; -void runtime·raisesigpipe(void); -void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool); -void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp); void runtime·sigpanic(void); void runtime·setitimer(int32, Itimerval*, Itimerval*); diff --git a/src/pkg/runtime/os_netbsd_386.c b/src/pkg/runtime/os_netbsd_386.c new file mode 100644 index 0000000000..23e9db3c1c --- /dev/null +++ b/src/pkg/runtime/os_netbsd_386.c @@ -0,0 +1,17 @@ +// 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_GOOS_GOARCH.h" +#include "os_GOOS.h" + +void +runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void)) +{ + mc->__gregs[REG_EIP] = (uint32)runtime·lwp_tramp; + mc->__gregs[REG_UESP] = (uint32)stack; + mc->__gregs[REG_EBX] = (uint32)mp; + mc->__gregs[REG_EDX] = (uint32)gp; + mc->__gregs[REG_ESI] = (uint32)fn; +} diff --git a/src/pkg/runtime/os_netbsd_amd64.c b/src/pkg/runtime/os_netbsd_amd64.c new file mode 100644 index 0000000000..226846cbb0 --- /dev/null +++ b/src/pkg/runtime/os_netbsd_amd64.c @@ -0,0 +1,18 @@ +// 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_GOOS_GOARCH.h" +#include "os_GOOS.h" + +void +runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void)) +{ + // Machine dependent mcontext initialisation for LWP. + mc->__gregs[REG_RIP] = (uint64)runtime·lwp_tramp; + mc->__gregs[REG_RSP] = (uint64)stack; + mc->__gregs[REG_R8] = (uint64)mp; + mc->__gregs[REG_R9] = (uint64)gp; + mc->__gregs[REG_R12] = (uint64)fn; +} diff --git a/src/pkg/runtime/os_netbsd_arm.c b/src/pkg/runtime/os_netbsd_arm.c new file mode 100644 index 0000000000..f188a30638 --- /dev/null +++ b/src/pkg/runtime/os_netbsd_arm.c @@ -0,0 +1,32 @@ +// Copyright 2013 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_GOOS_GOARCH.h" +#include "os_GOOS.h" + +void +runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void)) +{ + mc->r15 = (uint32)runtime·lwp_tramp; + mc->r13 = (uint32)stack; + mc->r0 = (uint32)mp; + mc->r1 = (uint32)gp; + mc->r2 = (uint32)fn; +} + +void +runtime·checkgoarm(void) +{ + // TODO(minux) +} + +#pragma textflag 7 +int64 +runtime·cputicks() { + // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1(). + // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler. + // TODO: need more entropy to better seed fastrand1. + return runtime·nanotime(); +} diff --git a/src/pkg/runtime/os_openbsd.c b/src/pkg/runtime/os_openbsd.c new file mode 100644 index 0000000000..01a2ef1195 --- /dev/null +++ b/src/pkg/runtime/os_openbsd.c @@ -0,0 +1,334 @@ +// Use of this source file is governed by a BSD-style +// license that can be found in the LICENSE file.` + +#include "runtime.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "signal_unix.h" +#include "stack.h" + +enum +{ + ESRCH = 3, + ENOTSUP = 91, + + // From OpenBSD's sys/time.h + CLOCK_REALTIME = 0, + CLOCK_VIRTUAL = 1, + CLOCK_PROF = 2, + CLOCK_MONOTONIC = 3 +}; + +extern SigTab runtime·sigtab[]; + +static Sigset sigset_none; +static Sigset sigset_all = ~(Sigset)0; + +extern int64 runtime·tfork(void *param, uintptr psize, M *mp, G *gp, void (*fn)(void)); +extern int32 runtime·thrsleep(void *ident, int32 clock_id, void *tsp, void *lock, const int32 *abort); +extern int32 runtime·thrwakeup(void *ident, int32 n); + +// From OpenBSD's +#define CTL_HW 6 +#define HW_NCPU 3 + +static int32 +getncpu(void) +{ + uint32 mib[2]; + uint32 out; + int32 ret; + uintptr nout; + + // Fetch hw.ncpu via sysctl. + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + nout = sizeof out; + out = 0; + ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0); + if(ret >= 0) + return out; + else + return 1; +} + +uintptr +runtime·semacreate(void) +{ + return 1; +} + +int32 +runtime·semasleep(int64 ns) +{ + Timespec ts; + + // spin-mutex lock + while(runtime·xchg(&m->waitsemalock, 1)) + runtime·osyield(); + + for(;;) { + // lock held + if(m->waitsemacount == 0) { + // sleep until semaphore != 0 or timeout. + // thrsleep unlocks m->waitsemalock. + if(ns < 0) + runtime·thrsleep(&m->waitsemacount, 0, nil, &m->waitsemalock, nil); + else { + ns += runtime·nanotime(); + ts.tv_sec = ns/1000000000LL; + ts.tv_nsec = ns%1000000000LL; + runtime·thrsleep(&m->waitsemacount, CLOCK_REALTIME, &ts, &m->waitsemalock, nil); + } + // reacquire lock + while(runtime·xchg(&m->waitsemalock, 1)) + runtime·osyield(); + } + + // lock held (again) + if(m->waitsemacount != 0) { + // semaphore is available. + m->waitsemacount--; + // spin-mutex unlock + runtime·atomicstore(&m->waitsemalock, 0); + return 0; // semaphore acquired + } + + // semaphore not available. + // if there is a timeout, stop now. + // otherwise keep trying. + if(ns >= 0) + break; + } + + // lock held but giving up + // spin-mutex unlock + runtime·atomicstore(&m->waitsemalock, 0); + return -1; +} + +void +runtime·semawakeup(M *mp) +{ + uint32 ret; + + // spin-mutex lock + while(runtime·xchg(&mp->waitsemalock, 1)) + runtime·osyield(); + mp->waitsemacount++; + ret = runtime·thrwakeup(&mp->waitsemacount, 1); + if(ret != 0 && ret != ESRCH) + runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret); + // spin-mutex unlock + runtime·atomicstore(&mp->waitsemalock, 0); +} + +void +runtime·newosproc(M *mp, void *stk) +{ + Tfork param; + Sigset oset; + int32 ret; + + if(0) { + runtime·printf( + "newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n", + stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp); + } + + mp->tls[0] = mp->id; // so 386 asm can find it + + param.tf_tcb = (byte*)&mp->tls[0]; + param.tf_tid = (int32*)&mp->procid; + param.tf_stack = stk; + + oset = runtime·sigprocmask(SIG_SETMASK, sigset_all); + ret = runtime·tfork((byte*)¶m, sizeof(param), mp, mp->g0, runtime·mstart); + runtime·sigprocmask(SIG_SETMASK, oset); + + if(ret < 0) { + runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret); + if (ret == -ENOTSUP) + runtime·printf("runtime: is kern.rthreads disabled?\n"); + runtime·throw("runtime.newosproc"); + } +} + +void +runtime·osinit(void) +{ + runtime·ncpu = getncpu(); +} + +void +runtime·get_random_data(byte **rnd, int32 *rnd_len) +{ + static byte urandom_data[HashRandomBytes]; + int32 fd; + fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0); + if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) { + *rnd = urandom_data; + *rnd_len = HashRandomBytes; + } else { + *rnd = nil; + *rnd_len = 0; + } + runtime·close(fd); +} + +void +runtime·goenvs(void) +{ + runtime·goenvs_unix(); +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +void +runtime·mpreinit(M *mp) +{ + mp->gsignal = runtime·malg(32*1024); +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +void +runtime·minit(void) +{ + // Initialize signal handling + runtime·signalstack((byte*)m->gsignal->stackguard - StackGuard, 32*1024); + runtime·sigprocmask(SIG_SETMASK, sigset_none); +} + +// Called from dropm to undo the effect of an minit. +void +runtime·unminit(void) +{ + runtime·signalstack(nil, 0); +} + +void +runtime·sigpanic(void) +{ + switch(g->sig) { + case SIGBUS: + if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); + 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) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); + 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); +} + +uintptr +runtime·memlimit(void) +{ + return 0; +} + +void +runtime·setprof(bool on) +{ + USED(on); +} + +static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n"; + +// This runs on a foreign stack, without an m or a g. No stack split. +#pragma textflag 7 +void +runtime·badcallback(void) +{ + runtime·write(2, badcallback, sizeof badcallback - 1); +} + +static int8 badsignal[] = "runtime: signal received on thread not created by Go: "; + +// This runs on a foreign stack, without an m or a g. No stack split. +#pragma textflag 7 +void +runtime·badsignal(int32 sig) +{ + if (sig == SIGPROF) { + return; // Ignore SIGPROFs intended for a non-Go thread. + } + runtime·write(2, badsignal, sizeof badsignal - 1); + if (0 <= sig && sig < NSIG) { + // Call runtime·findnull dynamically to circumvent static stack size check. + static int32 (*findnull)(byte*) = runtime·findnull; + runtime·write(2, runtime·sigtab[sig].name, findnull((byte*)runtime·sigtab[sig].name)); + } + runtime·write(2, "\n", 1); + runtime·exit(1); +} + +extern void runtime·sigtramp(void); + +typedef struct sigaction { + union { + void (*__sa_handler)(int32); + void (*__sa_sigaction)(int32, Siginfo*, void *); + } __sigaction_u; /* signal handler */ + uint32 sa_mask; /* signal mask to apply */ + int32 sa_flags; /* see signal options below */ +} Sigaction; + +void +runtime·setsig(int32 i, GoSighandler *fn, 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; + if(fn == runtime·sighandler) + fn = (void*)runtime·sigtramp; + sa.__sigaction_u.__sa_sigaction = (void*)fn; + runtime·sigaction(i, &sa, nil); +} + +GoSighandler* +runtime·getsig(int32 i) +{ + Sigaction sa; + + runtime·memclr((byte*)&sa, sizeof sa); + runtime·sigaction(i, nil, &sa); + if((void*)sa.__sigaction_u.__sa_sigaction == runtime·sigtramp) + return runtime·sighandler; + return (void*)sa.__sigaction_u.__sa_sigaction; +} + +void +runtime·signalstack(byte *p, int32 n) +{ + StackT st; + + st.ss_sp = (void*)p; + st.ss_size = n; + st.ss_flags = 0; + if(p == nil) + st.ss_flags = SS_DISABLE; + runtime·sigaltstack(&st, nil); +} diff --git a/src/pkg/runtime/os_openbsd.h b/src/pkg/runtime/os_openbsd.h index a599aad053..dbfa4b69f5 100644 --- a/src/pkg/runtime/os_openbsd.h +++ b/src/pkg/runtime/os_openbsd.h @@ -2,9 +2,6 @@ // 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) -#define SIGHUP 1 #define SS_DISABLE 4 #define SIG_BLOCK 1 @@ -13,14 +10,11 @@ struct sigaction; -void runtime·raisesigpipe(void); -void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool); void runtime·sigpanic(void); void runtime·setitimer(int32, Itimerval*, Itimerval*); void runtime·sigaction(int32, struct sigaction*, struct sigaction*); void runtime·sigaltstack(Sigaltstack*, Sigaltstack*); -void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp); Sigset runtime·sigprocmask(int32, Sigset); int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr); diff --git a/src/pkg/runtime/os_plan9.c b/src/pkg/runtime/os_plan9.c new file mode 100644 index 0000000000..338da8f216 --- /dev/null +++ b/src/pkg/runtime/os_plan9.c @@ -0,0 +1,344 @@ +// Copyright 2010 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 "os_GOOS.h" +#include "arch_GOARCH.h" + +int8 *goos = "plan9"; +extern SigTab runtime·sigtab[]; + +int32 runtime·postnote(int32, int8*); + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +void +runtime·mpreinit(M *mp) +{ + // Initialize stack and goroutine for note handling. + mp->gsignal = runtime·malg(32*1024); + mp->notesig = (int8*)runtime·malloc(ERRMAX*sizeof(int8)); + + // Initialize stack for handling strings from the + // errstr system call, as used in package syscall. + mp->errstr = (byte*)runtime·malloc(ERRMAX*sizeof(byte)); +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +void +runtime·minit(void) +{ + // Mask all SSE floating-point exceptions + // when running on the 64-bit kernel. + runtime·setfpmasks(); +} + +// Called from dropm to undo the effect of an minit. +void +runtime·unminit(void) +{ +} + + +static int32 +getproccount(void) +{ + int32 fd, i, n, ncpu; + byte buf[2048]; + + fd = runtime·open("/dev/sysstat", OREAD, 0); + if(fd < 0) + return 1; + ncpu = 0; + for(;;) { + n = runtime·read(fd, buf, sizeof buf); + if(n <= 0) + break; + for(i = 0; i < n; i++) { + if(buf[i] == '\n') + ncpu++; + } + } + runtime·close(fd); + return ncpu > 0 ? ncpu : 1; +} + +static int32 +getpid(void) +{ + byte b[20], *c; + int32 fd; + + runtime·memclr(b, sizeof(b)); + fd = runtime·open("#c/pid", 0, 0); + if(fd >= 0) { + runtime·read(fd, b, sizeof(b)); + runtime·close(fd); + } + c = b; + while(*c == ' ' || *c == '\t') + c++; + return runtime·atoi(c); +} + +void +runtime·osinit(void) +{ + runtime·ncpu = getproccount(); + m->procid = getpid(); + runtime·notify(runtime·sigtramp); +} + +void +runtime·get_random_data(byte **rnd, int32 *rnd_len) +{ + *rnd = nil; + *rnd_len = 0; +} + +void +runtime·goenvs(void) +{ +} + +void +runtime·initsig(void) +{ +} + +#pragma textflag 7 +void +runtime·osyield(void) +{ + runtime·sleep(0); +} + +void +runtime·usleep(uint32 µs) +{ + uint32 ms; + + ms = µs/1000; + if(ms == 0) + ms = 1; + runtime·sleep(ms); +} + +void +time·now(int64 sec, int32 nsec) +{ + int64 ns; + + ns = runtime·nanotime(); + sec = ns / 1000000000LL; + nsec = ns - sec * 1000000000LL; + FLUSH(&sec); + FLUSH(&nsec); +} + +void +runtime·itoa(int32 n, byte *p, uint32 len) +{ + byte *q, c; + uint32 i; + + if(len <= 1) + return; + + runtime·memclr(p, len); + q = p; + + if(n==0) { + *q++ = '0'; + USED(q); + return; + } + if(n < 0) { + *q++ = '-'; + p++; + n = -n; + } + for(i=0; n > 0 && i < len; i++) { + *q++ = '0' + (n%10); + n = n/10; + } + for(q--; q >= p; ) { + c = *p; + *p++ = *q; + *q-- = c; + } +} + +void +runtime·goexitsall(int8 *status) +{ + M *mp; + int32 pid; + + pid = getpid(); + for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink) + if(mp->procid != pid) + runtime·postnote(mp->procid, status); +} + +int32 +runtime·postnote(int32 pid, int8* msg) +{ + int32 fd, len; + uint8 buf[128]; + uint8 tmp[16]; + uint8 *p, *q; + + runtime·memclr(buf, sizeof buf); + + /* build path string /proc/pid/note */ + q = tmp; + p = buf; + runtime·itoa(pid, tmp, sizeof tmp); + runtime·memmove((void*)p, (void*)"/proc/", 6); + for(p += 6; *p++ = *q++; ); + p--; + runtime·memmove((void*)p, (void*)"/note", 5); + + fd = runtime·open((int8*)buf, OWRITE, 0); + if(fd < 0) + return -1; + + len = runtime·findnull((byte*)msg); + if(runtime·write(fd, msg, len) != len) { + runtime·close(fd); + return -1; + } + runtime·close(fd); + return 0; +} + +void +runtime·exit(int32 e) +{ + byte tmp[16]; + int8 *status; + + if(e == 0) + status = ""; + else { + /* build error string */ + runtime·itoa(e, tmp, sizeof tmp); + status = (int8*)tmp; + } + + runtime·goexitsall(status); + runtime·exits(status); +} + +void +runtime·newosproc(M *mp, void *stk) +{ + mp->tls[0] = mp->id; // so 386 asm can find it + if(0){ + runtime·printf("newosproc stk=%p m=%p g=%p rfork=%p id=%d/%d ostk=%p\n", + stk, mp, mp->g0, runtime·rfork, mp->id, (int32)mp->tls[0], &mp); + } + + if(runtime·rfork(RFPROC|RFMEM|RFNOWAIT, stk, mp, mp->g0, runtime·mstart) < 0) + runtime·throw("newosproc: rfork failed"); +} + +uintptr +runtime·semacreate(void) +{ + return 1; +} + +int32 +runtime·semasleep(int64 ns) +{ + int32 ret; + int32 ms; + + if(ns >= 0) { + if(ns/1000000 > 0x7fffffffll) + ms = 0x7fffffff; + else + ms = ns/1000000; + ret = runtime·plan9_tsemacquire(&m->waitsemacount, ms); + if(ret == 1) + return 0; // success + return -1; // timeout or interrupted + } + + while(runtime·plan9_semacquire(&m->waitsemacount, 1) < 0) { + /* interrupted; try again (c.f. lock_sema.c) */ + } + return 0; // success +} + +void +runtime·semawakeup(M *mp) +{ + runtime·plan9_semrelease(&mp->waitsemacount, 1); +} + +void +os·sigpipe(void) +{ + runtime·throw("too many writes on closed pipe"); +} + +void +runtime·sigpanic(void) +{ + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); + runtime·panicstring(m->notesig); + + if(g->sig == 1 || g->sig == 2) + runtime·throw("fault"); +} + +int32 +runtime·read(int32 fd, void *buf, int32 nbytes) +{ + return runtime·pread(fd, buf, nbytes, -1LL); +} + +int32 +runtime·write(int32 fd, void *buf, int32 nbytes) +{ + return runtime·pwrite(fd, buf, nbytes, -1LL); +} + +uintptr +runtime·memlimit(void) +{ + return 0; +} + +void +runtime·setprof(bool on) +{ + USED(on); +} + +static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n"; + +// This runs on a foreign stack, without an m or a g. No stack split. +#pragma textflag 7 +void +runtime·badcallback(void) +{ + runtime·pwrite(2, badcallback, sizeof badcallback - 1, -1LL); +} + +static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n"; + +// This runs on a foreign stack, without an m or a g. No stack split. +#pragma textflag 7 +void +runtime·badsignal(void) +{ + runtime·pwrite(2, badsignal, sizeof badsignal - 1, -1LL); + runtime·exits(badsignal); +} diff --git a/src/pkg/runtime/os_plan9.h b/src/pkg/runtime/os_plan9.h index f7cc597338..f0474cda54 100644 --- a/src/pkg/runtime/os_plan9.h +++ b/src/pkg/runtime/os_plan9.h @@ -16,7 +16,6 @@ int32 runtime·plan9_semrelease(uint32 *addr, int32 count); int32 runtime·notify(void (*fn)(void*, int8*)); int32 runtime·noted(int32); void runtime·sigtramp(void*, int8*); -int32 runtime·sighandler(void*, int8*, G*); void runtime·sigpanic(void); void runtime·goexitsall(int8*); void runtime·setfpmasks(void); diff --git a/src/pkg/runtime/os_plan9_386.c b/src/pkg/runtime/os_plan9_386.c new file mode 100644 index 0000000000..17bc117496 --- /dev/null +++ b/src/pkg/runtime/os_plan9_386.c @@ -0,0 +1,120 @@ +// Copyright 2010 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_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "signals_GOOS.h" + +void +runtime·dumpregs(Ureg *u) +{ + runtime·printf("ax %X\n", u->ax); + runtime·printf("bx %X\n", u->bx); + runtime·printf("cx %X\n", u->cx); + runtime·printf("dx %X\n", u->dx); + runtime·printf("di %X\n", u->di); + runtime·printf("si %X\n", u->si); + runtime·printf("bp %X\n", u->bp); + runtime·printf("sp %X\n", u->sp); + runtime·printf("pc %X\n", u->pc); + runtime·printf("flags %X\n", u->flags); + runtime·printf("cs %X\n", u->cs); + runtime·printf("fs %X\n", u->fs); + runtime·printf("gs %X\n", u->gs); +} + +int32 +runtime·sighandler(void *v, int8 *s, G *gp) +{ + Ureg *ureg; + uintptr *sp; + SigTab *sig, *nsig; + int32 len, i; + + if(!s) + return NCONT; + + len = runtime·findnull((byte*)s); + if(len <= 4 || runtime·mcmp((byte*)s, (byte*)"sys:", 4) != 0) + return NDFLT; + + nsig = nil; + sig = runtime·sigtab; + for(i=0; i < NSIG; i++) { + if(runtime·strstr((byte*)s, (byte*)sig->name)) { + nsig = sig; + break; + } + sig++; + } + + if(nsig == nil) + return NDFLT; + + ureg = v; + if(nsig->flags & SigPanic) { + if(gp == nil || m->notesig == 0) + goto Throw; + + // Save error string from sigtramp's stack, + // into gsignal->sigcode0, so we can reliably + // access it from the panic routines. + if(len > ERRMAX) + len = ERRMAX; + runtime·memmove((void*)m->notesig, (void*)s, len); + + gp->sig = i; + gp->sigpc = ureg->pc; + + // Only push runtime·sigpanic if ureg->pc != 0. + // If ureg->pc == 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(ureg->pc != 0) { + sp = (uintptr*)ureg->sp; + *--sp = ureg->pc; + ureg->sp = (uint32)sp; + } + ureg->pc = (uintptr)runtime·sigpanic; + return NCONT; + } + + if(!(nsig->flags & SigThrow)) + return NDFLT; + +Throw: + runtime·startpanic(); + + runtime·printf("%s\n", s); + runtime·printf("PC=%X\n", ureg->pc); + runtime·printf("\n"); + + if(runtime·gotraceback()) { + runtime·traceback((void*)ureg->pc, (void*)ureg->sp, 0, gp); + runtime·tracebackothers(gp); + runtime·dumpregs(ureg); + } + runtime·goexitsall(""); + runtime·exits(s); + + return 0; +} + + +void +runtime·sigenable(uint32 sig) +{ + USED(sig); +} + +void +runtime·resetcpuprofiler(int32 hz) +{ + // TODO: Enable profiling interrupts. + + m->profilehz = hz; +} diff --git a/src/pkg/runtime/os_plan9_amd64.c b/src/pkg/runtime/os_plan9_amd64.c new file mode 100644 index 0000000000..e4f946abce --- /dev/null +++ b/src/pkg/runtime/os_plan9_amd64.c @@ -0,0 +1,127 @@ +// Copyright 2010 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_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "signals_GOOS.h" + +void +runtime·dumpregs(Ureg *u) +{ + runtime·printf("ax %X\n", u->ax); + runtime·printf("bx %X\n", u->bx); + runtime·printf("cx %X\n", u->cx); + runtime·printf("dx %X\n", u->dx); + runtime·printf("di %X\n", u->di); + runtime·printf("si %X\n", u->si); + runtime·printf("bp %X\n", u->bp); + runtime·printf("sp %X\n", u->sp); + runtime·printf("r8 %X\n", u->r8); + runtime·printf("r9 %X\n", u->r9); + runtime·printf("r10 %X\n", u->r10); + runtime·printf("r11 %X\n", u->r11); + runtime·printf("r12 %X\n", u->r12); + runtime·printf("r13 %X\n", u->r13); + runtime·printf("r14 %X\n", u->r14); + runtime·printf("r15 %X\n", u->r15); + runtime·printf("ip %X\n", u->ip); + runtime·printf("flags %X\n", u->flags); + runtime·printf("cs %X\n", (uint64)u->cs); + runtime·printf("fs %X\n", (uint64)u->fs); + runtime·printf("gs %X\n", (uint64)u->gs); +} + +int32 +runtime·sighandler(void *v, int8 *s, G *gp) +{ + Ureg *ureg; + uintptr *sp; + SigTab *sig, *nsig; + int32 len, i; + + if(!s) + return NCONT; + + len = runtime·findnull((byte*)s); + if(len <= 4 || runtime·mcmp((byte*)s, (byte*)"sys:", 4) != 0) + return NDFLT; + + nsig = nil; + sig = runtime·sigtab; + for(i=0; i < NSIG; i++) { + if(runtime·strstr((byte*)s, (byte*)sig->name)) { + nsig = sig; + break; + } + sig++; + } + + if(nsig == nil) + return NDFLT; + + ureg = v; + if(nsig->flags & SigPanic) { + if(gp == nil || m->notesig == 0) + goto Throw; + + // Save error string from sigtramp's stack, + // into gsignal->sigcode0, so we can reliably + // access it from the panic routines. + if(len > ERRMAX) + len = ERRMAX; + runtime·memmove((void*)m->notesig, (void*)s, len); + + gp->sig = i; + gp->sigpc = ureg->ip; + + // Only push runtime·sigpanic if ureg->ip != 0. + // If ureg->ip == 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(ureg->ip != 0) { + sp = (uintptr*)ureg->sp; + *--sp = ureg->ip; + ureg->sp = (uint64)sp; + } + ureg->ip = (uintptr)runtime·sigpanic; + return NCONT; + } + + if(!(nsig->flags & SigThrow)) + return NDFLT; + +Throw: + runtime·startpanic(); + + runtime·printf("%s\n", s); + runtime·printf("PC=%X\n", ureg->ip); + runtime·printf("\n"); + + if(runtime·gotraceback()) { + runtime·traceback((void*)ureg->ip, (void*)ureg->sp, 0, gp); + runtime·tracebackothers(gp); + runtime·dumpregs(ureg); + } + runtime·goexitsall(""); + runtime·exits(s); + + return 0; +} + +void +runtime·sigenable(uint32 sig) +{ + USED(sig); +} + +void +runtime·resetcpuprofiler(int32 hz) +{ + // TODO: Enable profiling interrupts. + + m->profilehz = hz; +} diff --git a/src/pkg/runtime/os_windows.c b/src/pkg/runtime/os_windows.c new file mode 100644 index 0000000000..c80a38a374 --- /dev/null +++ b/src/pkg/runtime/os_windows.c @@ -0,0 +1,457 @@ +// 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 "type.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" + +#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll" +#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll" +#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll" +#pragma dynimport runtime·CreateWaitableTimer CreateWaitableTimerA "kernel32.dll" +#pragma dynimport runtime·CryptAcquireContextW CryptAcquireContextW "advapi32.dll" +#pragma dynimport runtime·CryptGenRandom CryptGenRandom "advapi32.dll" +#pragma dynimport runtime·CryptReleaseContext CryptReleaseContext "advapi32.dll" +#pragma dynimport runtime·DuplicateHandle DuplicateHandle "kernel32.dll" +#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll" +#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll" +#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll" +#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll" +#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll" +#pragma dynimport runtime·GetSystemInfo GetSystemInfo "kernel32.dll" +#pragma dynimport runtime·GetSystemTimeAsFileTime GetSystemTimeAsFileTime "kernel32.dll" +#pragma dynimport runtime·GetThreadContext GetThreadContext "kernel32.dll" +#pragma dynimport runtime·LoadLibrary LoadLibraryW "kernel32.dll" +#pragma dynimport runtime·ResumeThread ResumeThread "kernel32.dll" +#pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll" +#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll" +#pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll" +#pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll" +#pragma dynimport runtime·Sleep Sleep "kernel32.dll" +#pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll" +#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll" +#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll" +#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll" +#pragma dynimport runtime·NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll" + +extern void *runtime·NtWaitForSingleObject; + +extern void *runtime·CloseHandle; +extern void *runtime·CreateEvent; +extern void *runtime·CreateThread; +extern void *runtime·CreateWaitableTimer; +extern void *runtime·CryptAcquireContextW; +extern void *runtime·CryptGenRandom; +extern void *runtime·CryptReleaseContext; +extern void *runtime·DuplicateHandle; +extern void *runtime·ExitProcess; +extern void *runtime·FreeEnvironmentStringsW; +extern void *runtime·GetEnvironmentStringsW; +extern void *runtime·GetProcAddress; +extern void *runtime·GetStdHandle; +extern void *runtime·GetSystemInfo; +extern void *runtime·GetSystemTimeAsFileTime; +extern void *runtime·GetThreadContext; +extern void *runtime·LoadLibrary; +extern void *runtime·ResumeThread; +extern void *runtime·SetConsoleCtrlHandler; +extern void *runtime·SetEvent; +extern void *runtime·SetThreadPriority; +extern void *runtime·SetWaitableTimer; +extern void *runtime·Sleep; +extern void *runtime·SuspendThread; +extern void *runtime·timeBeginPeriod; +extern void *runtime·WaitForSingleObject; +extern void *runtime·WriteFile; + +static int32 +getproccount(void) +{ + SystemInfo info; + + runtime·stdcall(runtime·GetSystemInfo, 1, &info); + return info.dwNumberOfProcessors; +} + +void +runtime·osinit(void) +{ + // -1 = current process, -2 = current thread + runtime·stdcall(runtime·DuplicateHandle, 7, + (uintptr)-1, (uintptr)-2, (uintptr)-1, &m->thread, + (uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS); + runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1); + runtime·stdcall(runtime·timeBeginPeriod, 1, (uintptr)1); + runtime·ncpu = getproccount(); +} + +void +runtime·get_random_data(byte **rnd, int32 *rnd_len) +{ + uintptr handle; + *rnd = nil; + *rnd_len = 0; + if(runtime·stdcall(runtime·CryptAcquireContextW, 5, &handle, nil, nil, + (uintptr)1 /* PROV_RSA_FULL */, + (uintptr)0xf0000000U /* CRYPT_VERIFYCONTEXT */) != 0) { + static byte random_data[HashRandomBytes]; + if(runtime·stdcall(runtime·CryptGenRandom, 3, handle, (uintptr)HashRandomBytes, random_data)) { + *rnd = random_data; + *rnd_len = HashRandomBytes; + } + runtime·stdcall(runtime·CryptReleaseContext, 2, handle, (uintptr)0); + } +} + +void +runtime·goenvs(void) +{ + extern Slice syscall·envs; + + uint16 *env; + String *s; + int32 i, n; + uint16 *p; + + env = runtime·stdcall(runtime·GetEnvironmentStringsW, 0); + + n = 0; + for(p=env; *p; n++) + p += runtime·findnullw(p)+1; + + s = runtime·malloc(n*sizeof s[0]); + + p = env; + for(i=0; i 0x7fffffffLL) + ms = 0x7fffffff; + else { + ms = ns/1000000; + if(ms == 0) + ms = 1; + } + if(runtime·stdcall(runtime·WaitForSingleObject, 2, m->waitsema, ms) != 0) + return -1; // timeout + return 0; +} + +void +runtime·semawakeup(M *mp) +{ + runtime·stdcall(runtime·SetEvent, 1, mp->waitsema); +} + +uintptr +runtime·semacreate(void) +{ + return (uintptr)runtime·stdcall(runtime·CreateEvent, 4, (uintptr)0, (uintptr)0, (uintptr)0, (uintptr)0); +} + +#define STACK_SIZE_PARAM_IS_A_RESERVATION ((uintptr)0x00010000) + +void +runtime·newosproc(M *mp, void *stk) +{ + void *thandle; + + USED(stk); + + thandle = runtime·stdcall(runtime·CreateThread, 6, + nil, (uintptr)0x20000, runtime·tstart_stdcall, mp, + STACK_SIZE_PARAM_IS_A_RESERVATION, nil); + if(thandle == nil) { + runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror()); + runtime·throw("runtime.newosproc"); + } + runtime·atomicstorep(&mp->thread, thandle); +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +void +runtime·mpreinit(M *mp) +{ + USED(mp); +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +void +runtime·minit(void) +{ + runtime·install_exception_handler(); +} + +// Called from dropm to undo the effect of an minit. +void +runtime·unminit(void) +{ + runtime·remove_exception_handler(); +} + +int64 +runtime·nanotime(void) +{ + int64 filetime; + + runtime·stdcall(runtime·GetSystemTimeAsFileTime, 1, &filetime); + + // Filetime is 100s of nanoseconds since January 1, 1601. + // Convert to nanoseconds since January 1, 1970. + return (filetime - 116444736000000000LL) * 100LL; +} + +void +time·now(int64 sec, int32 usec) +{ + int64 ns; + + ns = runtime·nanotime(); + sec = ns / 1000000000LL; + usec = ns - sec * 1000000000LL; + FLUSH(&sec); + FLUSH(&usec); +} + +// Calling stdcall on os stack. +#pragma textflag 7 +void * +runtime·stdcall(void *fn, int32 count, ...) +{ + WinCall c; + + c.fn = fn; + c.n = count; + c.args = (uintptr*)&count + 1; + runtime·asmcgocall(runtime·asmstdcall, &c); + return (void*)c.r1; +} + +uint32 +runtime·issigpanic(uint32 code) +{ + switch(code) { + case EXCEPTION_ACCESS_VIOLATION: + case EXCEPTION_INT_DIVIDE_BY_ZERO: + case EXCEPTION_INT_OVERFLOW: + case EXCEPTION_FLT_DENORMAL_OPERAND: + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_FLT_INEXACT_RESULT: + case EXCEPTION_FLT_OVERFLOW: + case EXCEPTION_FLT_UNDERFLOW: + return 1; + } + return 0; +} + +void +runtime·sigpanic(void) +{ + switch(g->sig) { + case EXCEPTION_ACCESS_VIOLATION: + if(g->sigcode1 < 0x1000) { + if(g->sigpc == 0) + runtime·panicstring("call of nil func value"); + runtime·panicstring("invalid memory address or nil pointer dereference"); + } + runtime·printf("unexpected fault address %p\n", g->sigcode1); + runtime·throw("fault"); + case EXCEPTION_INT_DIVIDE_BY_ZERO: + runtime·panicstring("integer divide by zero"); + case EXCEPTION_INT_OVERFLOW: + runtime·panicstring("integer overflow"); + case EXCEPTION_FLT_DENORMAL_OPERAND: + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_FLT_INEXACT_RESULT: + case EXCEPTION_FLT_OVERFLOW: + case EXCEPTION_FLT_UNDERFLOW: + runtime·panicstring("floating point error"); + } + runtime·throw("fault"); +} + +extern void *runtime·sigtramp; + +void +runtime·initsig(void) +{ + // following line keeps sigtramp alive at link stage + // if there's a better way please write it here + void *p = runtime·sigtramp; + USED(p); +} + +uint32 +runtime·ctrlhandler1(uint32 type) +{ + int32 s; + + switch(type) { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: + s = SIGINT; + break; + default: + return 0; + } + + if(runtime·sigsend(s)) + return 1; + runtime·exit(2); // SIGINT, SIGTERM, etc + return 0; +} + +extern void runtime·dosigprof(Context *r, G *gp); +extern void runtime·profileloop(void); +static void *profiletimer; + +static void +profilem(M *mp) +{ + extern M runtime·m0; + extern uint32 runtime·tls0[]; + byte rbuf[sizeof(Context)+15]; + Context *r; + void *tls; + G *gp; + + tls = mp->tls; + if(mp == &runtime·m0) + tls = runtime·tls0; + gp = *(G**)tls; + + if(gp != nil && gp != mp->g0 && gp->status != Gsyscall) { + // align Context to 16 bytes + r = (Context*)((uintptr)(&rbuf[15]) & ~15); + r->ContextFlags = CONTEXT_CONTROL; + runtime·stdcall(runtime·GetThreadContext, 2, mp->thread, r); + runtime·dosigprof(r, gp); + } +} + +void +runtime·profileloop1(void) +{ + M *mp, *allm; + void *thread; + + runtime·stdcall(runtime·SetThreadPriority, 2, + (uintptr)-2, (uintptr)THREAD_PRIORITY_HIGHEST); + + for(;;) { + runtime·stdcall(runtime·WaitForSingleObject, 2, profiletimer, (uintptr)-1); + allm = runtime·atomicloadp(&runtime·allm); + for(mp = allm; mp != nil; mp = mp->alllink) { + thread = runtime·atomicloadp(&mp->thread); + if(thread == nil) + continue; + runtime·stdcall(runtime·SuspendThread, 1, thread); + if(mp->profilehz != 0) + profilem(mp); + runtime·stdcall(runtime·ResumeThread, 1, thread); + } + } +} + +void +runtime·resetcpuprofiler(int32 hz) +{ + static Lock lock; + void *timer, *thread; + int32 ms; + int64 due; + + runtime·lock(&lock); + if(profiletimer == nil) { + timer = runtime·stdcall(runtime·CreateWaitableTimer, 3, nil, nil, nil); + runtime·atomicstorep(&profiletimer, timer); + thread = runtime·stdcall(runtime·CreateThread, 6, + nil, nil, runtime·profileloop, nil, nil, nil); + runtime·stdcall(runtime·CloseHandle, 1, thread); + } + runtime·unlock(&lock); + + ms = 0; + due = 1LL<<63; + if(hz > 0) { + ms = 1000 / hz; + if(ms == 0) + ms = 1; + due = ms * -10000; + } + runtime·stdcall(runtime·SetWaitableTimer, 6, + profiletimer, &due, (uintptr)ms, nil, nil, nil); + runtime·atomicstore((uint32*)&m->profilehz, hz); +} + +void +os·sigpipe(void) +{ + runtime·throw("too many writes on closed pipe"); +} + +uintptr +runtime·memlimit(void) +{ + return 0; +} + +void +runtime·setprof(bool on) +{ + USED(on); +} + +int8 runtime·badcallbackmsg[] = "runtime: cgo callback on thread not created by Go.\n"; +int32 runtime·badcallbacklen = sizeof runtime·badcallbackmsg - 1; + +int8 runtime·badsignalmsg[] = "runtime: signal received on thread not created by Go.\n"; +int32 runtime·badsignallen = sizeof runtime·badsignalmsg - 1; diff --git a/src/pkg/runtime/os_windows_386.c b/src/pkg/runtime/os_windows_386.c new file mode 100644 index 0000000000..d76d5bf4bd --- /dev/null +++ b/src/pkg/runtime/os_windows_386.c @@ -0,0 +1,97 @@ +// 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_GOOS_GOARCH.h" +#include "os_GOOS.h" + +void +runtime·dumpregs(Context *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->SegCs); + runtime·printf("fs %x\n", r->SegFs); + runtime·printf("gs %x\n", r->SegGs); +} + +uint32 +runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) +{ + uintptr *sp; + + switch(info->ExceptionCode) { + case EXCEPTION_BREAKPOINT: + r->Eip--; // because 8l generates 2 bytes for INT3 + return 1; + } + + if(gp != nil && runtime·issigpanic(info->ExceptionCode)) { + // 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 = info->ExceptionCode; + gp->sigcode0 = info->ExceptionInformation[0]; + gp->sigcode1 = info->ExceptionInformation[1]; + 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 0; + } + + if(runtime·panicking) // traceback already printed + runtime·exit(2); + runtime·panicking = 1; + + runtime·printf("Exception %x %p %p\n", info->ExceptionCode, + info->ExceptionInformation[0], info->ExceptionInformation[1]); + + runtime·printf("PC=%x\n", r->Eip); + if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { + runtime·printf("signal arrived during cgo execution\n"); + gp = m->lockedg; + } + 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); + return 0; +} + +void +runtime·sigenable(uint32 sig) +{ + USED(sig); +} + +void +runtime·dosigprof(Context *r, G *gp) +{ + runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp); +} diff --git a/src/pkg/runtime/os_windows_amd64.c b/src/pkg/runtime/os_windows_amd64.c new file mode 100644 index 0000000000..3729aa57b7 --- /dev/null +++ b/src/pkg/runtime/os_windows_amd64.c @@ -0,0 +1,104 @@ +// Copyright 2011 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_GOOS_GOARCH.h" +#include "os_GOOS.h" + +void +runtime·dumpregs(Context *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->EFlags); + runtime·printf("cs %X\n", (uint64)r->SegCs); + runtime·printf("fs %X\n", (uint64)r->SegFs); + runtime·printf("gs %X\n", (uint64)r->SegGs); +} + +uint32 +runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) +{ + uintptr *sp; + + switch(info->ExceptionCode) { + case EXCEPTION_BREAKPOINT: + return 1; + } + + if(gp != nil && runtime·issigpanic(info->ExceptionCode)) { + // 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 = info->ExceptionCode; + gp->sigcode0 = info->ExceptionInformation[0]; + gp->sigcode1 = info->ExceptionInformation[1]; + 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 0; + } + + if(runtime·panicking) // traceback already printed + runtime·exit(2); + runtime·panicking = 1; + + runtime·printf("Exception %x %p %p\n", info->ExceptionCode, + info->ExceptionInformation[0], info->ExceptionInformation[1]); + + runtime·printf("PC=%X\n", r->Rip); + if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { + runtime·printf("signal arrived during cgo execution\n"); + gp = m->lockedg; + } + 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); + return 0; +} + +void +runtime·sigenable(uint32 sig) +{ + USED(sig); +} + +void +runtime·dosigprof(Context *r, G *gp) +{ + runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp); +} diff --git a/src/pkg/runtime/signal_386.c b/src/pkg/runtime/signal_386.c new file mode 100644 index 0000000000..1377de1400 --- /dev/null +++ b/src/pkg/runtime/signal_386.c @@ -0,0 +1,119 @@ +// Copyright 2013 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. + +// +build darwin freebsd linux netbsd openbsd + +#include "runtime.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "signal_GOOS_GOARCH.h" +#include "signals_GOOS.h" + +void +runtime·dumpregs(Siginfo *info, void *ctxt) +{ + USED(info); + USED(ctxt); + + runtime·printf("eax %x\n", SIG_EAX(info, ctxt)); + runtime·printf("ebx %x\n", SIG_EBX(info, ctxt)); + runtime·printf("ecx %x\n", SIG_ECX(info, ctxt)); + runtime·printf("edx %x\n", SIG_EDX(info, ctxt)); + runtime·printf("edi %x\n", SIG_EDI(info, ctxt)); + runtime·printf("esi %x\n", SIG_ESI(info, ctxt)); + runtime·printf("ebp %x\n", SIG_EBP(info, ctxt)); + runtime·printf("esp %x\n", SIG_ESP(info, ctxt)); + runtime·printf("eip %x\n", SIG_EIP(info, ctxt)); + runtime·printf("eflags %x\n", SIG_EFLAGS(info, ctxt)); + runtime·printf("cs %x\n", SIG_CS(info, ctxt)); + runtime·printf("fs %x\n", SIG_FS(info, ctxt)); + runtime·printf("gs %x\n", SIG_GS(info, ctxt)); +} + +void +runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) +{ + uintptr *sp; + SigTab *t; + + if(sig == SIGPROF) { + if(gp != m->g0 && gp != m->gsignal) + runtime·sigprof((byte*)SIG_EIP(info, ctxt), (byte*)SIG_ESP(info, ctxt), nil, gp); + return; + } + + t = &runtime·sigtab[sig]; + if(info->si_code != SI_USER && (t->flags & SigPanic)) { + if(gp == nil || gp == m->g0) + goto Throw; + + // 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 = SIG_CODE0(info, ctxt); + gp->sigcode1 = SIG_CODE1(info, ctxt); + gp->sigpc = SIG_EIP(info, ctxt); + +#ifdef GOOS_darwin + // 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 && gp->sigcode0 == 0) { + byte *pc; + pc = (byte*)gp->sigpc; + if(pc[0] == 0x66) // 16-bit instruction prefix + pc++; + if(pc[0] == 0xF6 || pc[0] == 0xF7) + gp->sigcode0 = FPE_INTDIV; + } +#endif + + // Only push runtime·sigpanic if eip != 0. + // If 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(SIG_EIP(info, ctxt) != 0) { + sp = (uintptr*)SIG_ESP(info, ctxt); + *--sp = SIG_EIP(info, ctxt); + SIG_ESP(info, ctxt) = (uintptr)sp; + } + SIG_EIP(info, ctxt) = (uintptr)runtime·sigpanic; + return; + } + + if(info->si_code == SI_USER || (t->flags & SigNotify)) + if(runtime·sigsend(sig)) + return; + if(t->flags & SigKill) + runtime·exit(2); + if(!(t->flags & SigThrow)) + return; + +Throw: + runtime·startpanic(); + + 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", SIG_EIP(info, ctxt)); + if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { + runtime·printf("signal arrived during cgo execution\n"); + gp = m->lockedg; + } + runtime·printf("\n"); + + if(runtime·gotraceback()){ + runtime·traceback((void*)SIG_EIP(info, ctxt), (void*)SIG_ESP(info, ctxt), 0, gp); + runtime·tracebackothers(gp); + runtime·dumpregs(info, ctxt); + } + + runtime·exit(2); +} diff --git a/src/pkg/runtime/signal_amd64.c b/src/pkg/runtime/signal_amd64.c new file mode 100644 index 0000000000..04ba038663 --- /dev/null +++ b/src/pkg/runtime/signal_amd64.c @@ -0,0 +1,129 @@ +// Copyright 2013 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. + +// +build darwin freebsd linux netbsd openbsd + +#include "runtime.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "signal_GOOS_GOARCH.h" +#include "signals_GOOS.h" + +void +runtime·dumpregs(Siginfo *info, void *ctxt) +{ + USED(info); + USED(ctxt); + + runtime·printf("rax %X\n", SIG_RAX(info, ctxt)); + runtime·printf("rbx %X\n", SIG_RBX(info, ctxt)); + runtime·printf("rcx %X\n", SIG_RCX(info, ctxt)); + runtime·printf("rdx %X\n", SIG_RDX(info, ctxt)); + runtime·printf("rdi %X\n", SIG_RDI(info, ctxt)); + runtime·printf("rsi %X\n", SIG_RSI(info, ctxt)); + runtime·printf("rbp %X\n", SIG_RBP(info, ctxt)); + runtime·printf("rsp %X\n", SIG_RSP(info, ctxt)); + runtime·printf("r8 %X\n", SIG_R8(info, ctxt) ); + runtime·printf("r9 %X\n", SIG_R9(info, ctxt) ); + runtime·printf("r10 %X\n", SIG_R10(info, ctxt)); + runtime·printf("r11 %X\n", SIG_R11(info, ctxt)); + runtime·printf("r12 %X\n", SIG_R12(info, ctxt)); + runtime·printf("r13 %X\n", SIG_R13(info, ctxt)); + runtime·printf("r14 %X\n", SIG_R14(info, ctxt)); + runtime·printf("r15 %X\n", SIG_R15(info, ctxt)); + runtime·printf("rip %X\n", SIG_RIP(info, ctxt)); + runtime·printf("rflags %X\n", SIG_RFLAGS(info, ctxt)); + runtime·printf("cs %X\n", SIG_CS(info, ctxt)); + runtime·printf("fs %X\n", SIG_FS(info, ctxt)); + runtime·printf("gs %X\n", SIG_GS(info, ctxt)); +} + +void +runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) +{ + uintptr *sp; + SigTab *t; + + if(sig == SIGPROF) { + if(gp != m->g0 && gp != m->gsignal) + runtime·sigprof((byte*)SIG_RIP(info, ctxt), (byte*)SIG_RSP(info, ctxt), nil, gp); + return; + } + + t = &runtime·sigtab[sig]; + if(info->si_code != SI_USER && (t->flags & SigPanic)) { + if(gp == nil || gp == m->g0) + goto Throw; + + // 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 = SIG_CODE0(info, ctxt); + gp->sigcode1 = SIG_CODE1(info, ctxt); + gp->sigpc = SIG_RIP(info, ctxt); + +#ifdef GOOS_darwin + // 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 && gp->sigcode0 == 0) { + byte *pc; + pc = (byte*)gp->sigpc; + 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) + gp->sigcode0 = FPE_INTDIV; + } +#endif + + // Only push runtime·sigpanic if rip != 0. + // If 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(SIG_RIP(info, ctxt) != 0) { + sp = (uintptr*)SIG_RSP(info, ctxt); + *--sp = SIG_RIP(info, ctxt); + SIG_RSP(info, ctxt) = (uintptr)sp; + } + SIG_RIP(info, ctxt) = (uintptr)runtime·sigpanic; + return; + } + + if(info->si_code == SI_USER || (t->flags & SigNotify)) + if(runtime·sigsend(sig)) + return; + if(t->flags & SigKill) + runtime·exit(2); + if(!(t->flags & SigThrow)) + return; + +Throw: + runtime·startpanic(); + + 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", SIG_RIP(info, ctxt)); + if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { + runtime·printf("signal arrived during cgo execution\n"); + gp = m->lockedg; + } + runtime·printf("\n"); + + if(runtime·gotraceback()){ + runtime·traceback((void*)SIG_RIP(info, ctxt), (void*)SIG_RSP(info, ctxt), 0, gp); + runtime·tracebackothers(gp); + runtime·dumpregs(info, ctxt); + } + + runtime·exit(2); +} diff --git a/src/pkg/runtime/signal_arm.c b/src/pkg/runtime/signal_arm.c new file mode 100644 index 0000000000..d493984ddb --- /dev/null +++ b/src/pkg/runtime/signal_arm.c @@ -0,0 +1,120 @@ +// 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. + +// +build darwin freebsd linux netbsd openbsd + +#include "runtime.h" +#include "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" +#include "signal_GOOS_GOARCH.h" +#include "signals_GOOS.h" + +void +runtime·dumpregs(Siginfo *info, void *ctxt) +{ + USED(info); + USED(ctxt); + + runtime·printf("trap %x\n", SIG_TRAP(info, ctxt)); + runtime·printf("error %x\n", SIG_ERROR(info, ctxt)); + runtime·printf("oldmask %x\n", SIG_OLDMASK(info, ctxt)); + runtime·printf("r0 %x\n", SIG_R0(info, ctxt)); + runtime·printf("r1 %x\n", SIG_R1(info, ctxt)); + runtime·printf("r2 %x\n", SIG_R2(info, ctxt)); + runtime·printf("r3 %x\n", SIG_R3(info, ctxt)); + runtime·printf("r4 %x\n", SIG_R4(info, ctxt)); + runtime·printf("r5 %x\n", SIG_R5(info, ctxt)); + runtime·printf("r6 %x\n", SIG_R6(info, ctxt)); + runtime·printf("r7 %x\n", SIG_R7(info, ctxt)); + runtime·printf("r8 %x\n", SIG_R8(info, ctxt)); + runtime·printf("r9 %x\n", SIG_R9(info, ctxt)); + runtime·printf("r10 %x\n", SIG_R10(info, ctxt)); + runtime·printf("fp %x\n", SIG_FP(info, ctxt)); + runtime·printf("ip %x\n", SIG_IP(info, ctxt)); + runtime·printf("sp %x\n", SIG_SP(info, ctxt)); + runtime·printf("lr %x\n", SIG_LR(info, ctxt)); + runtime·printf("pc %x\n", SIG_PC(info, ctxt)); + runtime·printf("cpsr %x\n", SIG_CPSR(info, ctxt)); + runtime·printf("fault %x\n", SIG_FAULT(info, ctxt)); +} + +void +runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) +{ + SigTab *t; + + if(sig == SIGPROF) { + if(gp != m->g0 && gp != m->gsignal) + runtime·sigprof((uint8*)SIG_PC(info, ctxt), (uint8*)SIG_SP(info, ctxt), (uint8*)SIG_LR(info, ctxt), gp); + return; + } + + t = &runtime·sigtab[sig]; + if(info->si_code != SI_USER && (t->flags & SigPanic)) { + if(gp == nil || gp == m->g0) + goto Throw; + + // 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 = SIG_CODE0(info, ctxt); + gp->sigcode1 = SIG_FAULT_ADDRESS(info, ctxt); + gp->sigpc = SIG_PC(info, ctxt); + + // We arrange lr, and pc to pretend the panicking + // function calls sigpanic directly. + // Always save LR to stack so that panics in leaf + // functions are correctly handled. This smashes + // the stack frame but we're not going back there + // anyway. + SIG_SP(info, ctxt) -= 4; + *(uint32*)SIG_SP(info, ctxt) = SIG_LR(info, ctxt); + // Don't bother saving PC if it's zero, which is + // probably a call to a nil func: the old link register + // is more useful in the stack trace. + if(gp->sigpc != 0) + SIG_LR(info, ctxt) = gp->sigpc; + // In case we are panicking from external C code + SIG_R10(info, ctxt) = (uintptr)gp; + SIG_R9(info, ctxt) = (uintptr)m; + SIG_PC(info, ctxt) = (uintptr)runtime·sigpanic; + return; + } + + if(info->si_code == SI_USER || (t->flags & SigNotify)) + if(runtime·sigsend(sig)) + return; + if(t->flags & SigKill) + runtime·exit(2); + if(!(t->flags & SigThrow)) + return; + +Throw: + 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", SIG_PC(info, ctxt)); + if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { + runtime·printf("signal arrived during cgo execution\n"); + gp = m->lockedg; + } + runtime·printf("\n"); + + if(runtime·gotraceback()){ + runtime·traceback((void*)SIG_PC(info, ctxt), (void*)SIG_SP(info, ctxt), (void*)SIG_LR(info, ctxt), gp); + runtime·tracebackothers(gp); + runtime·printf("\n"); + runtime·dumpregs(r); + } + + runtime·exit(2); +} diff --git a/src/pkg/runtime/signal_darwin_386.c b/src/pkg/runtime/signal_darwin_386.c deleted file mode 100644 index 132ca931b6..0000000000 --- a/src/pkg/runtime/signal_darwin_386.c +++ /dev/null @@ -1,155 +0,0 @@ -// 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_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "signals_GOOS.h" - -void -runtime·dumpregs(Regs32 *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); -} - -void -runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) -{ - Ucontext *uc; - Mcontext32 *mc; - Regs32 *r; - uintptr *sp; - byte *pc; - SigTab *t; - - uc = context; - mc = uc->uc_mcontext; - r = &mc->ss; - - if(sig == SIGPROF) { - if(gp != m->g0 && gp != m->gsignal) - runtime·sigprof((uint8*)r->eip, (uint8*)r->esp, nil, gp); - return; - } - - t = &runtime·sigtab[sig]; - if(info->si_code != SI_USER && (t->flags & SigPanic)) { - if(gp == nil || gp == m->g0) - goto Throw; - // 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(info->si_code == SI_USER || (t->flags & SigNotify)) - if(runtime·sigsend(sig)) - return; - if(t->flags & SigKill) - runtime·exit(2); - if(!(t->flags & SigThrow)) - return; - -Throw: - runtime·startpanic(); - - 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); - if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = m->lockedg; - } - 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·signalstack(byte *p, int32 n) -{ - StackT st; - - st.ss_sp = p; - st.ss_size = n; - st.ss_flags = 0; - if(p == nil) - st.ss_flags = SS_DISABLE; - runtime·sigaltstack(&st, nil); -} - -void -runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) -{ - Sigaction sa; - - // If SIGHUP handler is SIG_IGN, assume running - // under nohup and do not set explicit handler. - if(i == SIGHUP) { - runtime·memclr((byte*)&sa, sizeof sa); - runtime·sigaction(i, nil, &sa); - if(*(void**)sa.__sigaction_u == SIG_IGN) - return; - } - - 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 = (void*)runtime·sigtramp; // runtime·sigtramp's job is to call into real handler - *(uintptr*)sa.__sigaction_u = (uintptr)fn; - runtime·sigaction(i, &sa, nil); -} diff --git a/src/pkg/runtime/signal_darwin_386.h b/src/pkg/runtime/signal_darwin_386.h new file mode 100644 index 0000000000..5459e10a10 --- /dev/null +++ b/src/pkg/runtime/signal_darwin_386.h @@ -0,0 +1,23 @@ +// Copyright 2013 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_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext->ss) + +#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax) +#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx) +#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx) +#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx) +#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi) +#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi) +#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp) +#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp) +#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip) +#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags) + +#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).cs) +#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).fs) +#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gs) + +#define SIG_CODE0(info, ctxt) ((info)->si_code) +#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr) diff --git a/src/pkg/runtime/signal_darwin_amd64.c b/src/pkg/runtime/signal_darwin_amd64.c deleted file mode 100644 index 4b7256bf43..0000000000 --- a/src/pkg/runtime/signal_darwin_amd64.c +++ /dev/null @@ -1,165 +0,0 @@ -// 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_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "signals_GOOS.h" - -void -runtime·dumpregs(Regs64 *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); -} - -void -runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) -{ - Ucontext *uc; - Mcontext64 *mc; - Regs64 *r; - uintptr *sp; - byte *pc; - SigTab *t; - - uc = context; - mc = uc->uc_mcontext; - r = &mc->ss; - - if(sig == SIGPROF) { - if(gp != m->g0 && gp != m->gsignal) - runtime·sigprof((uint8*)r->rip, (uint8*)r->rsp, nil, gp); - return; - } - - t = &runtime·sigtab[sig]; - if(info->si_code != SI_USER && (t->flags & SigPanic)) { - if(gp == nil || gp == m->g0) - goto Throw; - // 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(info->si_code == SI_USER || (t->flags & SigNotify)) - if(runtime·sigsend(sig)) - return; - if(t->flags & SigKill) - runtime·exit(2); - if(!(t->flags & SigThrow)) - return; - -Throw: - runtime·startpanic(); - - 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); - if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = m->lockedg; - } - 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·signalstack(byte *p, int32 n) -{ - StackT st; - - st.ss_sp = p; - st.ss_size = n; - st.ss_flags = 0; - if(p == nil) - st.ss_flags = SS_DISABLE; - runtime·sigaltstack(&st, nil); -} - -void -runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) -{ - Sigaction sa; - - // If SIGHUP handler is SIG_IGN, assume running - // under nohup and do not set explicit handler. - if(i == SIGHUP) { - runtime·memclr((byte*)&sa, sizeof sa); - runtime·sigaction(i, nil, &sa); - if(*(void**)sa.__sigaction_u == SIG_IGN) - return; - } - - 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 = runtime·sigtramp; // runtime·sigtramp's job is to call into real handler - *(uintptr*)sa.__sigaction_u = (uintptr)fn; - runtime·sigaction(i, &sa, nil); -} diff --git a/src/pkg/runtime/signal_darwin_amd64.h b/src/pkg/runtime/signal_darwin_amd64.h new file mode 100644 index 0000000000..e3da6de3a0 --- /dev/null +++ b/src/pkg/runtime/signal_darwin_amd64.h @@ -0,0 +1,31 @@ +// Copyright 2013 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_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext->ss) + +#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax) +#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx) +#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx) +#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx) +#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi) +#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi) +#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp) +#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp) +#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8) +#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9) +#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10) +#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11) +#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12) +#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13) +#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14) +#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15) +#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip) +#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).rflags) + +#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).cs) +#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).fs) +#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gs) + +#define SIG_CODE0(info, ctxt) ((info)->si_code) +#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr) diff --git a/src/pkg/runtime/signal_freebsd_386.c b/src/pkg/runtime/signal_freebsd_386.c deleted file mode 100644 index 254e5e2772..0000000000 --- a/src/pkg/runtime/signal_freebsd_386.c +++ /dev/null @@ -1,154 +0,0 @@ -// 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_GOOS_GOARCH.h" -#include "signals_GOOS.h" -#include "os_GOOS.h" - -extern void runtime·sigtramp(void); - -typedef struct sigaction { - union { - void (*__sa_handler)(int32); - void (*__sa_sigaction)(int32, Siginfo*, void *); - } __sigaction_u; /* signal handler */ - int32 sa_flags; /* see signal options below */ - Sigset sa_mask; /* signal mask to apply */ -} Sigaction; - -void -runtime·dumpregs(Mcontext *r) -{ - runtime·printf("eax %x\n", r->mc_eax); - runtime·printf("ebx %x\n", r->mc_ebx); - runtime·printf("ecx %x\n", r->mc_ecx); - runtime·printf("edx %x\n", r->mc_edx); - runtime·printf("edi %x\n", r->mc_edi); - runtime·printf("esi %x\n", r->mc_esi); - runtime·printf("ebp %x\n", r->mc_ebp); - runtime·printf("esp %x\n", r->mc_esp); - runtime·printf("eip %x\n", r->mc_eip); - runtime·printf("eflags %x\n", r->mc_eflags); - runtime·printf("cs %x\n", r->mc_cs); - runtime·printf("fs %x\n", r->mc_fs); - runtime·printf("gs %x\n", r->mc_gs); -} - -void -runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) -{ - Ucontext *uc; - Mcontext *r; - uintptr *sp; - SigTab *t; - - uc = context; - r = &uc->uc_mcontext; - - if(sig == SIGPROF) { - runtime·sigprof((uint8*)r->mc_eip, (uint8*)r->mc_esp, nil, gp); - return; - } - - t = &runtime·sigtab[sig]; - if(info->si_code != SI_USER && (t->flags & SigPanic)) { - if(gp == nil || gp == m->g0) - goto Throw; - // 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->mc_eip; - - // Only push runtime·sigpanic if r->mc_eip != 0. - // If r->mc_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->mc_eip != 0) { - sp = (uintptr*)r->mc_esp; - *--sp = r->mc_eip; - r->mc_esp = (uintptr)sp; - } - r->mc_eip = (uintptr)runtime·sigpanic; - return; - } - - if(info->si_code == SI_USER || (t->flags & SigNotify)) - if(runtime·sigsend(sig)) - return; - if(t->flags & SigKill) - runtime·exit(2); - if(!(t->flags & SigThrow)) - return; - -Throw: - runtime·startpanic(); - - 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->mc_eip); - if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback()){ - runtime·traceback((void*)r->mc_eip, (void*)r->mc_esp, 0, gp); - runtime·tracebackothers(gp); - runtime·dumpregs(r); - } - - runtime·exit(2); -} - -void -runtime·signalstack(byte *p, int32 n) -{ - Sigaltstack st; - - st.ss_sp = (int8*)p; - st.ss_size = n; - st.ss_flags = 0; - if(p == nil) - st.ss_flags = SS_DISABLE; - runtime·sigaltstack(&st, nil); -} - -void -runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) -{ - Sigaction sa; - - // If SIGHUP handler is SIG_IGN, assume running - // under nohup and do not set explicit handler. - if(i == SIGHUP) { - runtime·memclr((byte*)&sa, sizeof sa); - runtime·sigaction(i, nil, &sa); - if(sa.__sigaction_u.__sa_sigaction == SIG_IGN) - return; - } - - runtime·memclr((byte*)&sa, sizeof sa); - sa.sa_flags = SA_SIGINFO|SA_ONSTACK; - if(restart) - sa.sa_flags |= SA_RESTART; - sa.sa_mask.__bits[0] = ~(uint32)0; - sa.sa_mask.__bits[1] = ~(uint32)0; - sa.sa_mask.__bits[2] = ~(uint32)0; - sa.sa_mask.__bits[3] = ~(uint32)0; - if (fn == runtime·sighandler) - fn = (void*)runtime·sigtramp; - sa.__sigaction_u.__sa_sigaction = (void*)fn; - runtime·sigaction(i, &sa, nil); -} diff --git a/src/pkg/runtime/signal_freebsd_386.h b/src/pkg/runtime/signal_freebsd_386.h new file mode 100644 index 0000000000..4f641fe760 --- /dev/null +++ b/src/pkg/runtime/signal_freebsd_386.h @@ -0,0 +1,23 @@ +// Copyright 2013 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_REGS(ctxt) (*((Ucontext*)(ctxt))->uc_mcontext) + +#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).mc_eax) +#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).mc_ebx) +#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).mc_ecx) +#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).mc_edx) +#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).mc_edi) +#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).mc_esi) +#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).mc_ebp) +#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).mc_esp) +#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).mc_eip) +#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_eflags) + +#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs) +#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_fs) +#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_gs) + +#define SIG_CODE0(info, ctxt) ((info)->si_code) +#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr) diff --git a/src/pkg/runtime/signal_freebsd_amd64.c b/src/pkg/runtime/signal_freebsd_amd64.c deleted file mode 100644 index 7dbf36075b..0000000000 --- a/src/pkg/runtime/signal_freebsd_amd64.c +++ /dev/null @@ -1,162 +0,0 @@ -// 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_GOOS_GOARCH.h" -#include "signals_GOOS.h" -#include "os_GOOS.h" - -extern void runtime·sigtramp(void); - -typedef struct sigaction { - union { - void (*__sa_handler)(int32); - void (*__sa_sigaction)(int32, Siginfo*, void *); - } __sigaction_u; /* signal handler */ - int32 sa_flags; /* see signal options below */ - Sigset sa_mask; /* signal mask to apply */ -} Sigaction; - -void -runtime·dumpregs(Mcontext *r) -{ - runtime·printf("rax %X\n", r->mc_rax); - runtime·printf("rbx %X\n", r->mc_rbx); - runtime·printf("rcx %X\n", r->mc_rcx); - runtime·printf("rdx %X\n", r->mc_rdx); - runtime·printf("rdi %X\n", r->mc_rdi); - runtime·printf("rsi %X\n", r->mc_rsi); - runtime·printf("rbp %X\n", r->mc_rbp); - runtime·printf("rsp %X\n", r->mc_rsp); - runtime·printf("r8 %X\n", r->mc_r8 ); - runtime·printf("r9 %X\n", r->mc_r9 ); - runtime·printf("r10 %X\n", r->mc_r10); - runtime·printf("r11 %X\n", r->mc_r11); - runtime·printf("r12 %X\n", r->mc_r12); - runtime·printf("r13 %X\n", r->mc_r13); - runtime·printf("r14 %X\n", r->mc_r14); - runtime·printf("r15 %X\n", r->mc_r15); - runtime·printf("rip %X\n", r->mc_rip); - runtime·printf("rflags %X\n", r->mc_flags); - runtime·printf("cs %X\n", r->mc_cs); - runtime·printf("fs %X\n", r->mc_fs); - runtime·printf("gs %X\n", r->mc_gs); -} - -void -runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) -{ - Ucontext *uc; - Mcontext *r; - uintptr *sp; - SigTab *t; - - uc = context; - r = &uc->uc_mcontext; - - if(sig == SIGPROF) { - runtime·sigprof((uint8*)r->mc_rip, (uint8*)r->mc_rsp, nil, gp); - return; - } - - t = &runtime·sigtab[sig]; - if(info->si_code != SI_USER && (t->flags & SigPanic)) { - if(gp == nil || gp == m->g0) - goto Throw; - // 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->mc_rip; - - // Only push runtime·sigpanic if r->mc_rip != 0. - // If r->mc_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->mc_rip != 0) { - sp = (uintptr*)r->mc_rsp; - *--sp = r->mc_rip; - r->mc_rsp = (uintptr)sp; - } - r->mc_rip = (uintptr)runtime·sigpanic; - return; - } - - if(info->si_code == SI_USER || (t->flags & SigNotify)) - if(runtime·sigsend(sig)) - return; - if(t->flags & SigKill) - runtime·exit(2); - if(!(t->flags & SigThrow)) - return; - -Throw: - runtime·startpanic(); - - 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->mc_rip); - if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback()){ - runtime·traceback((void*)r->mc_rip, (void*)r->mc_rsp, 0, gp); - runtime·tracebackothers(gp); - runtime·dumpregs(r); - } - - runtime·exit(2); -} - -void -runtime·signalstack(byte *p, int32 n) -{ - Sigaltstack st; - - st.ss_sp = (int8*)p; - st.ss_size = n; - st.ss_flags = 0; - if(p == nil) - st.ss_flags = SS_DISABLE; - runtime·sigaltstack(&st, nil); -} - -void -runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) -{ - Sigaction sa; - - // If SIGHUP handler is SIG_IGN, assume running - // under nohup and do not set explicit handler. - if(i == SIGHUP) { - runtime·memclr((byte*)&sa, sizeof sa); - runtime·sigaction(i, nil, &sa); - if(sa.__sigaction_u.__sa_sigaction == SIG_IGN) - return; - } - - runtime·memclr((byte*)&sa, sizeof sa); - sa.sa_flags = SA_SIGINFO|SA_ONSTACK; - if(restart) - sa.sa_flags |= SA_RESTART; - sa.sa_mask.__bits[0] = ~(uint32)0; - sa.sa_mask.__bits[1] = ~(uint32)0; - sa.sa_mask.__bits[2] = ~(uint32)0; - sa.sa_mask.__bits[3] = ~(uint32)0; - if (fn == runtime·sighandler) - fn = (void*)runtime·sigtramp; - sa.__sigaction_u.__sa_sigaction = (void*)fn; - runtime·sigaction(i, &sa, nil); -} diff --git a/src/pkg/runtime/signal_freebsd_amd64.h b/src/pkg/runtime/signal_freebsd_amd64.h new file mode 100644 index 0000000000..bde629fadd --- /dev/null +++ b/src/pkg/runtime/signal_freebsd_amd64.h @@ -0,0 +1,31 @@ +// Copyright 2013 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_REGS(ctxt) (*((Ucontext*)(ctxt))->uc_mcontext) + +#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).mc_rax) +#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).mc_rbx) +#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).mc_rcx) +#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).mc_rdx) +#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).mc_rdi) +#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).mc_rsi) +#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).mc_rbp) +#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).mc_rsp) +#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).mc_r8) +#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).mc_r9) +#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).mc_r10) +#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).mc_r11) +#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).mc_r12) +#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).mc_r13) +#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).mc_r14) +#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).mc_r15) +#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).mc_rip) +#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_rflags) + +#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs) +#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_fs) +#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_gs) + +#define SIG_CODE0(info, ctxt) ((info)->si_code) +#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr) diff --git a/src/pkg/runtime/signal_freebsd_arm.c b/src/pkg/runtime/signal_freebsd_arm.c deleted file mode 100644 index 50c3221bb4..0000000000 --- a/src/pkg/runtime/signal_freebsd_arm.c +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2012 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_GOOS_GOARCH.h" -#include "signals_GOOS.h" -#include "os_GOOS.h" - -#define r0 __gregs[0] -#define r1 __gregs[1] -#define r2 __gregs[2] -#define r3 __gregs[3] -#define r4 __gregs[4] -#define r5 __gregs[5] -#define r6 __gregs[6] -#define r7 __gregs[7] -#define r8 __gregs[8] -#define r9 __gregs[9] -#define r10 __gregs[10] -#define r11 __gregs[11] -#define r12 __gregs[12] -#define r13 __gregs[13] -#define r14 __gregs[14] -#define r15 __gregs[15] -#define cpsr __gregs[16] - -void -runtime·dumpregs(Mcontext *r) -{ - runtime·printf("r0 %x\n", r->r0); - runtime·printf("r1 %x\n", r->r1); - runtime·printf("r2 %x\n", r->r2); - runtime·printf("r3 %x\n", r->r3); - runtime·printf("r4 %x\n", r->r4); - runtime·printf("r5 %x\n", r->r5); - runtime·printf("r6 %x\n", r->r6); - runtime·printf("r7 %x\n", r->r7); - runtime·printf("r8 %x\n", r->r8); - runtime·printf("r9 %x\n", r->r9); - runtime·printf("r10 %x\n", r->r10); - runtime·printf("fp %x\n", r->r11); - runtime·printf("ip %x\n", r->r12); - runtime·printf("sp %x\n", r->r13); - runtime·printf("lr %x\n", r->r14); - runtime·printf("pc %x\n", r->r15); - runtime·printf("cpsr %x\n", r->cpsr); -} - -extern void runtime·sigtramp(void); - -typedef struct sigaction { - union { - void (*__sa_handler)(int32); - void (*__sa_sigaction)(int32, Siginfo*, void *); - } __sigaction_u; /* signal handler */ - int32 sa_flags; /* see signal options below */ - Sigset sa_mask; /* signal mask to apply */ -} Sigaction; - -void -runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) -{ - Ucontext *uc; - Mcontext *r; - SigTab *t; - - uc = context; - r = &uc->uc_mcontext; - - if(sig == SIGPROF) { - runtime·sigprof((uint8*)r->r15, (uint8*)r->r13, (uint8*)r->r14, gp); - return; - } - - t = &runtime·sigtab[sig]; - if(info->si_code != SI_USER && (t->flags & SigPanic)) { - if(gp == nil || gp == m->g0) - goto Throw; - // 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->r15; - - // Only push runtime·sigpanic if r->mc_rip != 0. - // If r->mc_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->r15 != 0) - r->r14 = r->r15; - // In case we are panicking from external C code - r->r10 = (uintptr)gp; - r->r9 = (uintptr)m; - r->r15 = (uintptr)runtime·sigpanic; - return; - } - - if(info->si_code == SI_USER || (t->flags & SigNotify)) - if(runtime·sigsend(sig)) - return; - if(t->flags & SigKill) - runtime·exit(2); - if(!(t->flags & SigThrow)) - return; - -Throw: - runtime·startpanic(); - - 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->r15); - if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback()){ - runtime·traceback((void*)r->r15, (void*)r->r13, (void*)r->r14, gp); - runtime·tracebackothers(gp); - runtime·printf("\n"); - runtime·dumpregs(r); - } - -// breakpoint(); - runtime·exit(2); -} - -void -runtime·signalstack(byte *p, int32 n) -{ - Sigaltstack st; - - st.ss_sp = (uint8*)p; - st.ss_size = n; - st.ss_flags = 0; - if(p == nil) - st.ss_flags = SS_DISABLE; - runtime·sigaltstack(&st, nil); -} - -void -runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) -{ - Sigaction sa; - - // If SIGHUP handler is SIG_IGN, assume running - // under nohup and do not set explicit handler. - if(i == SIGHUP) { - runtime·memclr((byte*)&sa, sizeof sa); - runtime·sigaction(i, nil, &sa); - if(sa.__sigaction_u.__sa_sigaction == SIG_IGN) - return; - } - - runtime·memclr((byte*)&sa, sizeof sa); - sa.sa_flags = SA_SIGINFO|SA_ONSTACK; - if(restart) - sa.sa_flags |= SA_RESTART; - sa.sa_mask.__bits[0] = ~(uint32)0; - sa.sa_mask.__bits[1] = ~(uint32)0; - sa.sa_mask.__bits[2] = ~(uint32)0; - sa.sa_mask.__bits[3] = ~(uint32)0; - if (fn == runtime·sighandler) - fn = (void*)runtime·sigtramp; - sa.__sigaction_u.__sa_sigaction = (void*)fn; - runtime·sigaction(i, &sa, nil); -} - -void -runtime·checkgoarm(void) -{ - // TODO(minux) -} - -#pragma textflag 7 -int64 -runtime·cputicks(void) -{ - // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1(). - // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler. - // TODO: need more entropy to better seed fastrand1. - return runtime·nanotime(); -} diff --git a/src/pkg/runtime/signal_freebsd_arm.h b/src/pkg/runtime/signal_freebsd_arm.h new file mode 100644 index 0000000000..4f26da3611 --- /dev/null +++ b/src/pkg/runtime/signal_freebsd_arm.h @@ -0,0 +1,27 @@ +// Copyright 2013 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_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext)) + +#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).__gregs[0]) +#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).__gregs[1]) +#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).__gregs[2]) +#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).__gregs[3]) +#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).__gregs[4]) +#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).__gregs[5]) +#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).__gregs[6]) +#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).__gregs[7]) +#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).__gregs[8]) +#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).__gregs[9]) +#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).__gregs[10]) +#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).__gregs[11]) +#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).__gregs[12]) +#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).__gregs[13]) +#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).__gregs[14]) +#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).__gregs[15]) +#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).__gregs[16]) +#define SIG_FAULT(info, ctxt) ((uintptr)(info)->si_addr) +#define SIG_TRAP(info, ctxt) (0) +#define SIG_ERROR(info, ctxt) (0) +#define SIG_OLDMASK(info, ctxt) (0) diff --git a/src/pkg/runtime/signal_linux_386.c b/src/pkg/runtime/signal_linux_386.c deleted file mode 100644 index 07aed332b9..0000000000 --- a/src/pkg/runtime/signal_linux_386.c +++ /dev/null @@ -1,180 +0,0 @@ -// 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_GOOS_GOARCH.h" -#include "signals_GOOS.h" -#include "os_GOOS.h" - -void -runtime·dumpregs(Sigcontext *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); -} - -/* - * This assembler routine takes the args from registers, puts them on the stack, - * and calls sighandler(). - */ -extern void runtime·sigtramp(void); -extern void runtime·sigreturn(void); // calls runtime·sigreturn - -void -runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) -{ - Ucontext *uc; - Sigcontext *r; - uintptr *sp; - SigTab *t; - - uc = context; - r = &uc->uc_mcontext; - - if(sig == SIGPROF) { - runtime·sigprof((uint8*)r->eip, (uint8*)r->esp, nil, gp); - return; - } - - t = &runtime·sigtab[sig]; - if(info->si_code != SI_USER && (t->flags & SigPanic)) { - if(gp == nil || gp == m->g0) - goto Throw; - // 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)[3]; - 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(info->si_code == SI_USER || (t->flags & SigNotify)) - if(runtime·sigsend(sig)) - return; - if(t->flags & SigKill) - runtime·exit(2); - if(!(t->flags & SigThrow)) - return; - -Throw: - runtime·startpanic(); - - 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); - if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = m->lockedg; - } - 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·signalstack(byte *p, int32 n) -{ - Sigaltstack st; - - st.ss_sp = p; - st.ss_size = n; - st.ss_flags = 0; - if(p == nil) - st.ss_flags = SS_DISABLE; - runtime·sigaltstack(&st, nil); -} - -void -runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) -{ - Sigaction sa; - - // If SIGHUP handler is SIG_IGN, assume running - // under nohup and do not set explicit handler. - if(i == SIGHUP) { - runtime·memclr((byte*)&sa, sizeof sa); - if(runtime·rt_sigaction(i, nil, &sa, sizeof(sa.sa_mask)) != 0) - runtime·throw("rt_sigaction read failure"); - if(sa.k_sa_handler == SIG_IGN) - return; - } - - runtime·memclr((byte*)&sa, sizeof sa); - sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER; - if(restart) - sa.sa_flags |= SA_RESTART; - sa.sa_mask = ~0ULL; - sa.sa_restorer = (void*)runtime·sigreturn; - if(fn == runtime·sighandler) - fn = (void*)runtime·sigtramp; - sa.k_sa_handler = fn; - if(runtime·rt_sigaction(i, &sa, nil, sizeof(sa.sa_mask)) != 0) - runtime·throw("rt_sigaction failure"); -} - -#define AT_NULL 0 -#define AT_RANDOM 25 -#define AT_SYSINFO 32 -extern uint32 runtime·_vdso; - -#pragma textflag 7 -void -runtime·linux_setup_vdso(int32 argc, byte **argv) -{ - byte **envp; - uint32 *auxv; - - // skip envp to get to ELF auxiliary vector. - for(envp = &argv[argc+1]; *envp != nil; envp++) - ; - envp++; - - for(auxv=(uint32*)envp; auxv[0] != AT_NULL; auxv += 2) { - if(auxv[0] == AT_SYSINFO) { - runtime·_vdso = auxv[1]; - continue; - } - if(auxv[0] == AT_RANDOM) { - runtime·startup_random_data = (byte*)auxv[1]; - runtime·startup_random_data_len = 16; - continue; - } - } -} diff --git a/src/pkg/runtime/signal_linux_386.h b/src/pkg/runtime/signal_linux_386.h new file mode 100644 index 0000000000..f77f1c9d51 --- /dev/null +++ b/src/pkg/runtime/signal_linux_386.h @@ -0,0 +1,24 @@ +// Copyright 2013 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_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext)) + +#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax) +#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx) +#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx) +#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx) +#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi) +#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi) +#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp) +#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp) +#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip) +#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags) + +#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).cs) +#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).fs) +#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gs) + +#define SIG_CODE0(info, ctxt) ((info)->si_code) +#define SIG_CODE1(info, ctxt) (((uintptr*)(info))[2]) + diff --git a/src/pkg/runtime/signal_linux_amd64.c b/src/pkg/runtime/signal_linux_amd64.c deleted file mode 100644 index c4e39a6ab0..0000000000 --- a/src/pkg/runtime/signal_linux_amd64.c +++ /dev/null @@ -1,162 +0,0 @@ -// 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_GOOS_GOARCH.h" -#include "signals_GOOS.h" -#include "os_GOOS.h" - -void -runtime·dumpregs(Sigcontext *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->eflags); - runtime·printf("cs %X\n", (uint64)r->cs); - runtime·printf("fs %X\n", (uint64)r->fs); - runtime·printf("gs %X\n", (uint64)r->gs); -} - -/* - * This assembler routine takes the args from registers, puts them on the stack, - * and calls sighandler(). - */ -extern void runtime·sigtramp(void); -extern void runtime·sigreturn(void); // calls runtime·sigreturn - -void -runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) -{ - Ucontext *uc; - Mcontext *mc; - Sigcontext *r; - uintptr *sp; - SigTab *t; - - uc = context; - mc = &uc->uc_mcontext; - r = (Sigcontext*)mc; // same layout, more conveient names - - if(sig == SIGPROF) { - runtime·sigprof((uint8*)r->rip, (uint8*)r->rsp, nil, gp); - return; - } - - t = &runtime·sigtab[sig]; - if(info->si_code != SI_USER && (t->flags & SigPanic)) { - if(gp == nil || gp == m->g0) - goto Throw; - // 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)[2]; - 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(info->si_code == SI_USER || (t->flags & SigNotify)) - if(runtime·sigsend(sig)) - return; - if(t->flags & SigKill) - runtime·exit(2); - if(!(t->flags & SigThrow)) - return; - -Throw: - runtime·startpanic(); - - 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); - if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = m->lockedg; - } - 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·signalstack(byte *p, int32 n) -{ - Sigaltstack st; - - st.ss_sp = p; - st.ss_size = n; - st.ss_flags = 0; - if(p == nil) - st.ss_flags = SS_DISABLE; - runtime·sigaltstack(&st, nil); -} - -void -runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) -{ - Sigaction sa; - - // If SIGHUP handler is SIG_IGN, assume running - // under nohup and do not set explicit handler. - if(i == SIGHUP) { - runtime·memclr((byte*)&sa, sizeof sa); - if(runtime·rt_sigaction(i, nil, &sa, sizeof(sa.sa_mask)) != 0) - runtime·throw("rt_sigaction read failure"); - if(sa.sa_handler == SIG_IGN) - return; - } - - runtime·memclr((byte*)&sa, sizeof sa); - sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER; - if(restart) - sa.sa_flags |= SA_RESTART; - sa.sa_mask = ~0ULL; - // TODO(adonovan): Linux manpage says "sa_restorer element is - // obsolete and should not be used". Avoid it here, and test. - sa.sa_restorer = (void*)runtime·sigreturn; - if(fn == runtime·sighandler) - fn = (void*)runtime·sigtramp; - sa.sa_handler = fn; - if(runtime·rt_sigaction(i, &sa, nil, sizeof(sa.sa_mask)) != 0) - runtime·throw("rt_sigaction failure"); -} diff --git a/src/pkg/runtime/signal_linux_amd64.h b/src/pkg/runtime/signal_linux_amd64.h new file mode 100644 index 0000000000..5a9a3e5da4 --- /dev/null +++ b/src/pkg/runtime/signal_linux_amd64.h @@ -0,0 +1,32 @@ +// Copyright 2013 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_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext)) + +#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax) +#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx) +#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx) +#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx) +#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi) +#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi) +#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp) +#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp) +#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8) +#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9) +#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10) +#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11) +#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12) +#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13) +#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14) +#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15) +#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip) +#define SIG_RFLAGS(info, ctxt) ((uint64)SIG_REGS(ctxt).eflags) + +#define SIG_CS(info, ctxt) ((uint64)SIG_REGS(ctxt).cs) +#define SIG_FS(info, ctxt) ((uint64)SIG_REGS(ctxt).fs) +#define SIG_GS(info, ctxt) ((uint64)SIG_REGS(ctxt).gs) + +#define SIG_CODE0(info, ctxt) ((info)->si_code) +#define SIG_CODE1(info, ctxt) (((uintptr*)(info))[2]) + diff --git a/src/pkg/runtime/signal_linux_arm.c b/src/pkg/runtime/signal_linux_arm.c deleted file mode 100644 index c26caa7cdb..0000000000 --- a/src/pkg/runtime/signal_linux_arm.c +++ /dev/null @@ -1,241 +0,0 @@ -// 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_GOOS_GOARCH.h" -#include "signals_GOOS.h" -#include "os_GOOS.h" - -void -runtime·dumpregs(Sigcontext *r) -{ - runtime·printf("trap %x\n", r->trap_no); - runtime·printf("error %x\n", r->error_code); - runtime·printf("oldmask %x\n", r->oldmask); - runtime·printf("r0 %x\n", r->arm_r0); - runtime·printf("r1 %x\n", r->arm_r1); - runtime·printf("r2 %x\n", r->arm_r2); - runtime·printf("r3 %x\n", r->arm_r3); - runtime·printf("r4 %x\n", r->arm_r4); - runtime·printf("r5 %x\n", r->arm_r5); - runtime·printf("r6 %x\n", r->arm_r6); - runtime·printf("r7 %x\n", r->arm_r7); - runtime·printf("r8 %x\n", r->arm_r8); - runtime·printf("r9 %x\n", r->arm_r9); - runtime·printf("r10 %x\n", r->arm_r10); - runtime·printf("fp %x\n", r->arm_fp); - runtime·printf("ip %x\n", r->arm_ip); - runtime·printf("sp %x\n", r->arm_sp); - runtime·printf("lr %x\n", r->arm_lr); - runtime·printf("pc %x\n", r->arm_pc); - runtime·printf("cpsr %x\n", r->arm_cpsr); - runtime·printf("fault %x\n", r->fault_address); -} - -/* - * This assembler routine takes the args from registers, puts them on the stack, - * and calls sighandler(). - */ -extern void runtime·sigtramp(void); -extern void runtime·sigreturn(void); // calls runtime·sigreturn - -void -runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) -{ - Ucontext *uc; - Sigcontext *r; - SigTab *t; - - uc = context; - r = &uc->uc_mcontext; - - if(sig == SIGPROF) { - runtime·sigprof((uint8*)r->arm_pc, (uint8*)r->arm_sp, (uint8*)r->arm_lr, gp); - return; - } - - t = &runtime·sigtab[sig]; - if(info->si_code != SI_USER && (t->flags & SigPanic)) { - if(gp == nil || gp == m->g0) - goto Throw; - // 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 = r->fault_address; - gp->sigpc = r->arm_pc; - - // We arrange lr, and pc to pretend the panicking - // function calls sigpanic directly. - // Always save LR to stack so that panics in leaf - // functions are correctly handled. This smashes - // the stack frame but we're not going back there - // anyway. - r->arm_sp -= 4; - *(uint32 *)r->arm_sp = r->arm_lr; - // Don't bother saving PC if it's zero, which is - // probably a call to a nil func: the old link register - // is more useful in the stack trace. - if(r->arm_pc != 0) - r->arm_lr = r->arm_pc; - // In case we are panicking from external C code - r->arm_r10 = (uintptr)gp; - r->arm_r9 = (uintptr)m; - r->arm_pc = (uintptr)runtime·sigpanic; - return; - } - - if(info->si_code == SI_USER || (t->flags & SigNotify)) - if(runtime·sigsend(sig)) - return; - if(t->flags & SigKill) - runtime·exit(2); - if(!(t->flags & SigThrow)) - return; - -Throw: - 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->arm_pc); - if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback()){ - runtime·traceback((void*)r->arm_pc, (void*)r->arm_sp, (void*)r->arm_lr, gp); - runtime·tracebackothers(gp); - runtime·printf("\n"); - runtime·dumpregs(r); - } - -// breakpoint(); - runtime·exit(2); -} - -void -runtime·signalstack(byte *p, int32 n) -{ - Sigaltstack st; - - st.ss_sp = p; - st.ss_size = n; - st.ss_flags = 0; - if(p == nil) - st.ss_flags = SS_DISABLE; - runtime·sigaltstack(&st, nil); -} - -void -runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) -{ - Sigaction sa; - - // If SIGHUP handler is SIG_IGN, assume running - // under nohup and do not set explicit handler. - if(i == SIGHUP) { - runtime·memclr((byte*)&sa, sizeof sa); - if(runtime·rt_sigaction(i, nil, &sa, sizeof(sa.sa_mask)) != 0) - runtime·throw("rt_sigaction read failure"); - if(sa.sa_handler == SIG_IGN) - return; - } - - runtime·memclr((byte*)&sa, sizeof sa); - sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER; - if(restart) - sa.sa_flags |= SA_RESTART; - sa.sa_mask = ~0ULL; - sa.sa_restorer = (void*)runtime·sigreturn; - if(fn == runtime·sighandler) - fn = (void*)runtime·sigtramp; - sa.sa_handler = fn; - if(runtime·rt_sigaction(i, &sa, nil, sizeof(sa.sa_mask)) != 0) - runtime·throw("rt_sigaction failure"); -} - -#define AT_NULL 0 -#define AT_PLATFORM 15 // introduced in at least 2.6.11 -#define AT_HWCAP 16 // introduced in at least 2.6.11 -#define AT_RANDOM 25 // introduced in 2.6.29 -#define HWCAP_VFP (1 << 6) // introduced in at least 2.6.11 -#define HWCAP_VFPv3 (1 << 13) // introduced in 2.6.30 -static uint32 runtime·randomNumber; -uint8 runtime·armArch = 6; // we default to ARMv6 -uint32 runtime·hwcap; // set by setup_auxv -uint8 runtime·goarm; // set by 5l - -void -runtime·checkgoarm(void) -{ - if(runtime·goarm > 5 && !(runtime·hwcap & HWCAP_VFP)) { - runtime·printf("runtime: this CPU has no floating point hardware, so it cannot run\n"); - runtime·printf("this GOARM=%d binary. Recompile using GOARM=5.\n", runtime·goarm); - runtime·exit(1); - } - if(runtime·goarm > 6 && !(runtime·hwcap & HWCAP_VFPv3)) { - runtime·printf("runtime: this CPU has no VFPv3 floating point hardware, so it cannot run\n"); - runtime·printf("this GOARM=%d binary. Recompile using GOARM=6.\n", runtime·goarm); - runtime·exit(1); - } -} - -#pragma textflag 7 -void -runtime·setup_auxv(int32 argc, void *argv_list) -{ - byte **argv; - byte **envp; - byte *rnd; - uint32 *auxv; - uint32 t; - - argv = &argv_list; - - // skip envp to get to ELF auxiliary vector. - for(envp = &argv[argc+1]; *envp != nil; envp++) - ; - envp++; - - for(auxv=(uint32*)envp; auxv[0] != AT_NULL; auxv += 2) { - switch(auxv[0]) { - case AT_RANDOM: // kernel provided 16-byte worth of random data - if(auxv[1]) { - rnd = (byte*)auxv[1]; - runtime·randomNumber = rnd[4] | rnd[5]<<8 | rnd[6]<<16 | rnd[7]<<24; - } - break; - case AT_PLATFORM: // v5l, v6l, v7l - if(auxv[1]) { - t = *(uint8*)(auxv[1]+1); - if(t >= '5' && t <= '7') - runtime·armArch = t - '0'; - } - break; - case AT_HWCAP: // CPU capability bit flags - runtime·hwcap = auxv[1]; - break; - } - } -} - -#pragma textflag 7 -int64 -runtime·cputicks(void) -{ - // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1(). - // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler. - // runtime·randomNumber provides better seeding of fastrand1. - return runtime·nanotime() + runtime·randomNumber; -} diff --git a/src/pkg/runtime/signal_linux_arm.h b/src/pkg/runtime/signal_linux_arm.h new file mode 100644 index 0000000000..cc16c079e8 --- /dev/null +++ b/src/pkg/runtime/signal_linux_arm.h @@ -0,0 +1,27 @@ +// Copyright 2013 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_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext)) + +#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).arm_r0) +#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).arm_r1) +#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).arm_r2) +#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).arm_r3) +#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).arm_r4) +#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).arm_r5) +#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).arm_r6) +#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).arm_r7) +#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).arm_r8) +#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).arm_r9) +#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).arm_r10) +#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).arm_fp) +#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).arm_ip) +#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).arm_sp) +#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).arm_lr) +#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).arm_pc) +#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).arm_cpsr) +#define SIG_FAULT(info, ctxt) (SIG_REGS(ctxt).fault_address) +#define SIG_TRAP(info, ctxt) (SIG_REGS(ctxt).trap_no) +#define SIG_ERROR(info, ctxt) (SIG_REGS(ctxt).error_code) +#define SIG_OLDMASK(info, ctxt) (SIG_REGS(ctxt).oldmask) diff --git a/src/pkg/runtime/signal_netbsd_386.c b/src/pkg/runtime/signal_netbsd_386.c deleted file mode 100644 index 08744c4251..0000000000 --- a/src/pkg/runtime/signal_netbsd_386.c +++ /dev/null @@ -1,164 +0,0 @@ -// 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_GOOS_GOARCH.h" -#include "signals_GOOS.h" -#include "os_GOOS.h" - -extern void runtime·lwp_tramp(void); -extern void runtime·sigtramp(void); - -typedef struct sigaction { - union { - void (*_sa_handler)(int32); - void (*_sa_sigaction)(int32, Siginfo*, void *); - } _sa_u; /* signal handler */ - uint32 sa_mask[4]; /* signal mask to apply */ - int32 sa_flags; /* see signal options below */ -} Sigaction; - -void -runtime·dumpregs(McontextT *mc) -{ - runtime·printf("eax %x\n", mc->__gregs[REG_EAX]); - runtime·printf("ebx %x\n", mc->__gregs[REG_EBX]); - runtime·printf("ecx %x\n", mc->__gregs[REG_ECX]); - runtime·printf("edx %x\n", mc->__gregs[REG_EDX]); - runtime·printf("edi %x\n", mc->__gregs[REG_EDI]); - runtime·printf("esi %x\n", mc->__gregs[REG_ESI]); - runtime·printf("ebp %x\n", mc->__gregs[REG_EBP]); - runtime·printf("esp %x\n", mc->__gregs[REG_UESP]); - runtime·printf("eip %x\n", mc->__gregs[REG_EIP]); - runtime·printf("eflags %x\n", mc->__gregs[REG_EFL]); - runtime·printf("cs %x\n", mc->__gregs[REG_CS]); - runtime·printf("fs %x\n", mc->__gregs[REG_FS]); - runtime·printf("gs %x\n", mc->__gregs[REG_GS]); -} - -void -runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) -{ - UcontextT *uc = context; - McontextT *mc = &uc->uc_mcontext; - uintptr *sp; - SigTab *t; - - if(sig == SIGPROF) { - runtime·sigprof((uint8*)mc->__gregs[REG_EIP], - (uint8*)mc->__gregs[REG_UESP], nil, gp); - return; - } - - t = &runtime·sigtab[sig]; - if(info->_code != SI_USER && (t->flags & SigPanic)) { - if(gp == nil || gp == m->g0) - goto Throw; - // Make it look like a call to the signal func. - // We need to pass arguments out of band since - // augmenting the stack frame would break - // the unwinding code. - gp->sig = sig; - gp->sigcode0 = info->_code; - gp->sigcode1 = *(uintptr*)&info->_reason[0]; /* _addr */ - gp->sigpc = mc->__gregs[REG_EIP]; - - // Only push runtime·sigpanic if __gregs[REG_EIP] != 0. - // If __gregs[REG_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(mc->__gregs[REG_EIP] != 0) { - sp = (uintptr*)mc->__gregs[REG_UESP]; - *--sp = mc->__gregs[REG_EIP]; - mc->__gregs[REG_UESP] = (uintptr)sp; - } - mc->__gregs[REG_EIP] = (uintptr)runtime·sigpanic; - return; - } - - if(info->_code == SI_USER || (t->flags & SigNotify)) - if(runtime·sigsend(sig)) - return; - if(t->flags & SigKill) - runtime·exit(2); - if(!(t->flags & SigThrow)) - return; - -Throw: - runtime·startpanic(); - - 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", mc->__gregs[REG_EIP]); - if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback()){ - runtime·traceback((void*)mc->__gregs[REG_EIP], - (void*)mc->__gregs[REG_UESP], 0, gp); - runtime·tracebackothers(gp); - runtime·dumpregs(mc); - } - - runtime·exit(2); -} - -void -runtime·signalstack(byte *p, int32 n) -{ - Sigaltstack st; - - st.ss_sp = p; - st.ss_size = n; - st.ss_flags = 0; - if(p == nil) - st.ss_flags = SS_DISABLE; - runtime·sigaltstack(&st, nil); -} - -void -runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) -{ - Sigaction sa; - - // If SIGHUP handler is SIG_IGN, assume running - // under nohup and do not set explicit handler. - if(i == SIGHUP) { - runtime·memclr((byte*)&sa, sizeof sa); - runtime·sigaction(i, nil, &sa); - if(sa._sa_u._sa_sigaction == SIG_IGN) - return; - } - - runtime·memclr((byte*)&sa, sizeof sa); - sa.sa_flags = SA_SIGINFO|SA_ONSTACK; - if(restart) - sa.sa_flags |= SA_RESTART; - sa.sa_mask[0] = ~0U; - sa.sa_mask[1] = ~0U; - sa.sa_mask[2] = ~0U; - sa.sa_mask[3] = ~0U; - if (fn == runtime·sighandler) - fn = (void*)runtime·sigtramp; - sa._sa_u._sa_sigaction = (void*)fn; - runtime·sigaction(i, &sa, nil); -} - -void -runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void)) -{ - mc->__gregs[REG_EIP] = (uint32)runtime·lwp_tramp; - mc->__gregs[REG_UESP] = (uint32)stack; - mc->__gregs[REG_EBX] = (uint32)mp; - mc->__gregs[REG_EDX] = (uint32)gp; - mc->__gregs[REG_ESI] = (uint32)fn; -} diff --git a/src/pkg/runtime/signal_netbsd_386.h b/src/pkg/runtime/signal_netbsd_386.h new file mode 100644 index 0000000000..65df84da0d --- /dev/null +++ b/src/pkg/runtime/signal_netbsd_386.h @@ -0,0 +1,23 @@ +// Copyright 2013 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_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext)) + +#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EAX]) +#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EBX]) +#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_ECX]) +#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EDX]) +#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EDI]) +#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_ESI]) +#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EBP]) +#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_ESP]) +#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EIP]) +#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EFLAGS]) + +#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CS]) +#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_FS]) +#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_GS]) + +#define SIG_CODE0(info, ctxt) ((info)->_code) +#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0]) diff --git a/src/pkg/runtime/signal_netbsd_amd64.c b/src/pkg/runtime/signal_netbsd_amd64.c deleted file mode 100644 index 46afb682ba..0000000000 --- a/src/pkg/runtime/signal_netbsd_amd64.c +++ /dev/null @@ -1,172 +0,0 @@ -// 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_GOOS_GOARCH.h" -#include "signals_GOOS.h" -#include "os_GOOS.h" - -extern void runtime·lwp_tramp(void); -extern void runtime·sigtramp(void); - -typedef struct sigaction { - union { - void (*_sa_handler)(int32); - void (*_sa_sigaction)(int32, Siginfo*, void *); - } _sa_u; /* signal handler */ - uint32 sa_mask[4]; /* signal mask to apply */ - int32 sa_flags; /* see signal options below */ -} Sigaction; - -void -runtime·dumpregs(McontextT *mc) -{ - runtime·printf("rax %X\n", mc->__gregs[REG_RAX]); - runtime·printf("rbx %X\n", mc->__gregs[REG_RBX]); - runtime·printf("rcx %X\n", mc->__gregs[REG_RCX]); - runtime·printf("rdx %X\n", mc->__gregs[REG_RDX]); - runtime·printf("rdi %X\n", mc->__gregs[REG_RDI]); - runtime·printf("rsi %X\n", mc->__gregs[REG_RSI]); - runtime·printf("rbp %X\n", mc->__gregs[REG_RBP]); - runtime·printf("rsp %X\n", mc->__gregs[REG_RSP]); - runtime·printf("r8 %X\n", mc->__gregs[REG_R8]); - runtime·printf("r9 %X\n", mc->__gregs[REG_R9]); - runtime·printf("r10 %X\n", mc->__gregs[REG_R10]); - runtime·printf("r11 %X\n", mc->__gregs[REG_R11]); - runtime·printf("r12 %X\n", mc->__gregs[REG_R12]); - runtime·printf("r13 %X\n", mc->__gregs[REG_R13]); - runtime·printf("r14 %X\n", mc->__gregs[REG_R14]); - runtime·printf("r15 %X\n", mc->__gregs[REG_R15]); - runtime·printf("rip %X\n", mc->__gregs[REG_RIP]); - runtime·printf("rflags %X\n", mc->__gregs[REG_RFLAGS]); - runtime·printf("cs %X\n", mc->__gregs[REG_CS]); - runtime·printf("fs %X\n", mc->__gregs[REG_FS]); - runtime·printf("gs %X\n", mc->__gregs[REG_GS]); -} - -void -runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) -{ - UcontextT *uc = context; - McontextT *mc = &uc->uc_mcontext; - uintptr *sp; - SigTab *t; - - if(sig == SIGPROF) { - runtime·sigprof((uint8*)mc->__gregs[REG_RIP], - (uint8*)mc->__gregs[REG_RSP], nil, gp); - return; - } - - t = &runtime·sigtab[sig]; - if(info->_code != SI_USER && (t->flags & SigPanic)) { - if(gp == nil || gp == m->g0) - goto Throw; - // Make it look like a call to the signal func. - // We need to pass arguments out of band since augmenting the - // stack frame would break the unwinding code. - gp->sig = sig; - gp->sigcode0 = info->_code; - gp->sigcode1 = *(uintptr*)&info->_reason[0]; /* _addr */ - gp->sigpc = mc->__gregs[REG_RIP]; - - // Only push runtime·sigpanic if __gregs[REG_RIP] != 0. - // If __gregs[REG_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(mc->__gregs[REG_RIP] != 0) { - sp = (uintptr*)mc->__gregs[REG_RSP]; - *--sp = mc->__gregs[REG_RIP]; - mc->__gregs[REG_RSP] = (uintptr)sp; - } - mc->__gregs[REG_RIP] = (uintptr)runtime·sigpanic; - return; - } - - if(info->_code == SI_USER || (t->flags & SigNotify)) - if(runtime·sigsend(sig)) - return; - if(t->flags & SigKill) - runtime·exit(2); - if(!(t->flags & SigThrow)) - return; - -Throw: - runtime·startpanic(); - - 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", mc->__gregs[REG_RIP]); - if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback()){ - runtime·traceback((void*)mc->__gregs[REG_RIP], - (void*)mc->__gregs[REG_RSP], 0, gp); - runtime·tracebackothers(gp); - runtime·dumpregs(mc); - } - - runtime·exit(2); -} - -void -runtime·signalstack(byte *p, int32 n) -{ - Sigaltstack st; - - st.ss_sp = p; - st.ss_size = n; - st.ss_flags = 0; - if(p == nil) - st.ss_flags = SS_DISABLE; - runtime·sigaltstack(&st, nil); -} - -void -runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) -{ - Sigaction sa; - - // If SIGHUP handler is SIG_IGN, assume running - // under nohup and do not set explicit handler. - if(i == SIGHUP) { - runtime·memclr((byte*)&sa, sizeof sa); - runtime·sigaction(i, nil, &sa); - if(sa._sa_u._sa_sigaction == SIG_IGN) - return; - } - - runtime·memclr((byte*)&sa, sizeof sa); - sa.sa_flags = SA_SIGINFO|SA_ONSTACK; - if(restart) - sa.sa_flags |= SA_RESTART; - sa.sa_mask[0] = ~0U; - sa.sa_mask[1] = ~0U; - sa.sa_mask[2] = ~0U; - sa.sa_mask[3] = ~0U; - if (fn == runtime·sighandler) - fn = (void*)runtime·sigtramp; - sa._sa_u._sa_sigaction = (void*)fn; - runtime·sigaction(i, &sa, nil); -} - -void -runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void)) -{ - // Machine dependent mcontext initialisation for LWP. - mc->__gregs[REG_RIP] = (uint64)runtime·lwp_tramp; - mc->__gregs[REG_RSP] = (uint64)stack; - mc->__gregs[REG_R8] = (uint64)mp; - mc->__gregs[REG_R9] = (uint64)gp; - mc->__gregs[REG_R12] = (uint64)fn; -} diff --git a/src/pkg/runtime/signal_netbsd_amd64.h b/src/pkg/runtime/signal_netbsd_amd64.h new file mode 100644 index 0000000000..a374039aab --- /dev/null +++ b/src/pkg/runtime/signal_netbsd_amd64.h @@ -0,0 +1,31 @@ +// Copyright 2013 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_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext)) + +#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RAX]) +#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RBX]) +#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RCX]) +#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RDX]) +#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RDI]) +#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RSI]) +#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RBP]) +#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RSP]) +#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R8]) +#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R9]) +#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R10]) +#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R11]) +#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R12]) +#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R13]) +#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R14]) +#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R15]) +#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RIP]) +#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RFLAGS]) + +#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CS]) +#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_FS]) +#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_GS]) + +#define SIG_CODE0(info, ctxt) ((info)->_code) +#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0]) diff --git a/src/pkg/runtime/signal_netbsd_arm.c b/src/pkg/runtime/signal_netbsd_arm.c deleted file mode 100644 index 97f62687bd..0000000000 --- a/src/pkg/runtime/signal_netbsd_arm.c +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2013 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_GOOS_GOARCH.h" -#include "signals_GOOS.h" -#include "os_GOOS.h" - -#define r0 __gregs[0] -#define r1 __gregs[1] -#define r2 __gregs[2] -#define r3 __gregs[3] -#define r4 __gregs[4] -#define r5 __gregs[5] -#define r6 __gregs[6] -#define r7 __gregs[7] -#define r8 __gregs[8] -#define r9 __gregs[9] -#define r10 __gregs[10] -#define r11 __gregs[11] -#define r12 __gregs[12] -#define r13 __gregs[13] -#define r14 __gregs[14] -#define r15 __gregs[15] -#define cpsr __gregs[16] - -void -runtime·dumpregs(McontextT *r) -{ - runtime·printf("r0 %x\n", r->r0); - runtime·printf("r1 %x\n", r->r1); - runtime·printf("r2 %x\n", r->r2); - runtime·printf("r3 %x\n", r->r3); - runtime·printf("r4 %x\n", r->r4); - runtime·printf("r5 %x\n", r->r5); - runtime·printf("r6 %x\n", r->r6); - runtime·printf("r7 %x\n", r->r7); - runtime·printf("r8 %x\n", r->r8); - runtime·printf("r9 %x\n", r->r9); - runtime·printf("r10 %x\n", r->r10); - runtime·printf("fp %x\n", r->r11); - runtime·printf("ip %x\n", r->r12); - runtime·printf("sp %x\n", r->r13); - runtime·printf("lr %x\n", r->r14); - runtime·printf("pc %x\n", r->r15); - runtime·printf("cpsr %x\n", r->cpsr); -} - -extern void runtime·lwp_tramp(void); -extern void runtime·sigtramp(void); - -typedef struct sigaction { - union { - void (*_sa_handler)(int32); - void (*_sa_sigaction)(int32, Siginfo*, void *); - } _sa_u; /* signal handler */ - uint32 sa_mask[4]; /* signal mask to apply */ - int32 sa_flags; /* see signal options below */ -} Sigaction; - -void -runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) -{ - UcontextT *uc; - McontextT *r; - SigTab *t; - - uc = context; - r = &uc->uc_mcontext; - - if(sig == SIGPROF) { - runtime·sigprof((uint8*)r->r15, (uint8*)r->r13, (uint8*)r->r14, gp); - return; - } - - t = &runtime·sigtab[sig]; - if(info->_code != SI_USER && (t->flags & SigPanic)) { - if(gp == nil || gp == m->g0) - goto Throw; - // Make it look like a call to the signal func. - // We have to pass arguments out of band since - // augmenting the stack frame would break - // the unwinding code. - gp->sig = sig; - gp->sigcode0 = info->_code; - gp->sigcode1 = *(uintptr*)&info->_reason[0]; /* _addr */ - gp->sigpc = r->r15; - - // We arrange lr, and pc to pretend the panicking - // function calls sigpanic directly. - // Always save LR to stack so that panics in leaf - // functions are correctly handled. This smashes - // the stack frame but we're not going back there - // anyway. - r->r13 -= 4; - *(uint32 *)r->r13 = r->r14; - // Don't bother saving PC if it's zero, which is - // probably a call to a nil func: the old link register - // is more useful in the stack trace. - if(r->r15 != 0) - r->r14 = r->r15; - // In case we are panicking from external C code - r->r10 = (uintptr)gp; - r->r9 = (uintptr)m; - r->r15 = (uintptr)runtime·sigpanic; - return; - } - - if(info->_code == SI_USER || (t->flags & SigNotify)) - if(runtime·sigsend(sig)) - return; - if(t->flags & SigKill) - runtime·exit(2); - if(!(t->flags & SigThrow)) - return; - -Throw: - runtime·startpanic(); - - 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->r15); - if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback()){ - runtime·traceback((void*)r->r15, (void*)r->r13, (void*)r->r14, gp); - runtime·tracebackothers(gp); - runtime·printf("\n"); - runtime·dumpregs(r); - } - -// breakpoint(); - runtime·exit(2); -} - -void -runtime·signalstack(byte *p, int32 n) -{ - Sigaltstack st; - - st.ss_sp = (uint8*)p; - st.ss_size = n; - st.ss_flags = 0; - if(p == nil) - st.ss_flags = SS_DISABLE; - runtime·sigaltstack(&st, nil); -} - -void -runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) -{ - Sigaction sa; - - // If SIGHUP handler is SIG_IGN, assume running - // under nohup and do not set explicit handler. - if(i == SIGHUP) { - runtime·memclr((byte*)&sa, sizeof sa); - runtime·sigaction(i, nil, &sa); - if(sa._sa_u._sa_sigaction == SIG_IGN) - return; - } - - runtime·memclr((byte*)&sa, sizeof sa); - sa.sa_flags = SA_SIGINFO|SA_ONSTACK; - if(restart) - sa.sa_flags |= SA_RESTART; - sa.sa_mask[0] = ~0U; - sa.sa_mask[1] = ~0U; - sa.sa_mask[2] = ~0U; - sa.sa_mask[3] = ~0U; - if (fn == runtime·sighandler) - fn = (void*)runtime·sigtramp; - sa._sa_u._sa_sigaction = (void*)fn; - runtime·sigaction(i, &sa, nil); -} - -void -runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void)) -{ - mc->r15 = (uint32)runtime·lwp_tramp; - mc->r13 = (uint32)stack; - mc->r0 = (uint32)mp; - mc->r1 = (uint32)gp; - mc->r2 = (uint32)fn; -} - -void -runtime·checkgoarm(void) -{ - // TODO(minux) -} - -#pragma textflag 7 -int64 -runtime·cputicks() { - // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1(). - // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler. - // TODO: need more entropy to better seed fastrand1. - return runtime·nanotime(); -} diff --git a/src/pkg/runtime/signal_netbsd_arm.h b/src/pkg/runtime/signal_netbsd_arm.h new file mode 100644 index 0000000000..ffdca0e32f --- /dev/null +++ b/src/pkg/runtime/signal_netbsd_arm.h @@ -0,0 +1,27 @@ +// Copyright 2013 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_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext)) + +#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).__gregs[0]) +#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).__gregs[1]) +#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).__gregs[2]) +#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).__gregs[3]) +#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).__gregs[4]) +#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).__gregs[5]) +#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).__gregs[6]) +#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).__gregs[7]) +#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).__gregs[8]) +#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).__gregs[9]) +#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).__gregs[10]) +#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).__gregs[11]) +#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).__gregs[12]) +#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).__gregs[13]) +#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).__gregs[14]) +#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).__gregs[15]) +#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).__gregs[16]) +#define SIG_FAULT(info, ctxt) (*(uintptr*)&(info)->_reason[0]) +#define SIG_TRAP(info, ctxt) (0) +#define SIG_ERROR(info, ctxt) (0) +#define SIG_OLDMASK(info, ctxt) (0) diff --git a/src/pkg/runtime/signal_openbsd_386.c b/src/pkg/runtime/signal_openbsd_386.c deleted file mode 100644 index 516797c8d2..0000000000 --- a/src/pkg/runtime/signal_openbsd_386.c +++ /dev/null @@ -1,147 +0,0 @@ -// 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_GOOS_GOARCH.h" -#include "signals_GOOS.h" -#include "os_GOOS.h" - -extern void runtime·sigtramp(void); - -typedef struct sigaction { - union { - void (*__sa_handler)(int32); - void (*__sa_sigaction)(int32, Siginfo*, void *); - } __sigaction_u; /* signal handler */ - uint32 sa_mask; /* signal mask to apply */ - int32 sa_flags; /* see signal options below */ -} Sigaction; - -void -runtime·dumpregs(Sigcontext *r) -{ - runtime·printf("eax %x\n", r->sc_eax); - runtime·printf("ebx %x\n", r->sc_ebx); - runtime·printf("ecx %x\n", r->sc_ecx); - runtime·printf("edx %x\n", r->sc_edx); - runtime·printf("edi %x\n", r->sc_edi); - runtime·printf("esi %x\n", r->sc_esi); - runtime·printf("ebp %x\n", r->sc_ebp); - runtime·printf("esp %x\n", r->sc_esp); - runtime·printf("eip %x\n", r->sc_eip); - runtime·printf("eflags %x\n", r->sc_eflags); - runtime·printf("cs %x\n", r->sc_cs); - runtime·printf("fs %x\n", r->sc_fs); - runtime·printf("gs %x\n", r->sc_gs); -} - -void -runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) -{ - Sigcontext *r = context; - uintptr *sp; - SigTab *t; - - if(sig == SIGPROF) { - runtime·sigprof((uint8*)r->sc_eip, (uint8*)r->sc_esp, nil, gp); - return; - } - - t = &runtime·sigtab[sig]; - if(info->si_code != SI_USER && (t->flags & SigPanic)) { - if(gp == nil || gp == m->g0) - goto Throw; - // 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*)((byte*)info + 12); /* si_addr */ - gp->sigpc = r->sc_eip; - - // Only push runtime·sigpanic if r->sc_eip != 0. - // If r->sc_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->sc_eip != 0) { - sp = (uintptr*)r->sc_esp; - *--sp = r->sc_eip; - r->sc_esp = (uintptr)sp; - } - r->sc_eip = (uintptr)runtime·sigpanic; - return; - } - - if(info->si_code == SI_USER || (t->flags & SigNotify)) - if(runtime·sigsend(sig)) - return; - if(t->flags & SigKill) - runtime·exit(2); - if(!(t->flags & SigThrow)) - return; - -Throw: - runtime·startpanic(); - - 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->sc_eip); - if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback()){ - runtime·traceback((void*)r->sc_eip, (void*)r->sc_esp, 0, gp); - runtime·tracebackothers(gp); - runtime·dumpregs(r); - } - - runtime·exit(2); -} - -void -runtime·signalstack(byte *p, int32 n) -{ - Sigaltstack st; - - st.ss_sp = p; - st.ss_size = n; - st.ss_flags = 0; - if(p == nil) - st.ss_flags = SS_DISABLE; - runtime·sigaltstack(&st, nil); -} - -void -runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) -{ - Sigaction sa; - - // If SIGHUP handler is SIG_IGN, assume running - // under nohup and do not set explicit handler. - if(i == SIGHUP) { - runtime·memclr((byte*)&sa, sizeof sa); - runtime·sigaction(i, nil, &sa); - if(sa.__sigaction_u.__sa_sigaction == SIG_IGN) - return; - } - - runtime·memclr((byte*)&sa, sizeof sa); - sa.sa_flags = SA_SIGINFO|SA_ONSTACK; - if(restart) - sa.sa_flags |= SA_RESTART; - sa.sa_mask = ~0ULL; - if (fn == runtime·sighandler) - fn = (void*)runtime·sigtramp; - sa.__sigaction_u.__sa_sigaction = (void*)fn; - runtime·sigaction(i, &sa, nil); -} diff --git a/src/pkg/runtime/signal_openbsd_386.h b/src/pkg/runtime/signal_openbsd_386.h new file mode 100644 index 0000000000..0ba66ab9f1 --- /dev/null +++ b/src/pkg/runtime/signal_openbsd_386.h @@ -0,0 +1,23 @@ +// Copyright 2013 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_REGS(ctxt) (*(Sigcontext*)(ctxt)) + +#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).sc_eax) +#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).sc_ebx) +#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).sc_ecx) +#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).sc_edx) +#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).sc_edi) +#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).sc_esi) +#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).sc_ebp) +#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).sc_esp) +#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).sc_eip) +#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).sc_eflags) + +#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).sc_cs) +#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).sc_fs) +#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).sc_gs) + +#define SIG_CODE0(info, ctxt) ((info)->si_code) +#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr) diff --git a/src/pkg/runtime/signal_openbsd_amd64.c b/src/pkg/runtime/signal_openbsd_amd64.c deleted file mode 100644 index 0d0db770b5..0000000000 --- a/src/pkg/runtime/signal_openbsd_amd64.c +++ /dev/null @@ -1,156 +0,0 @@ -// 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_GOOS_GOARCH.h" -#include "signals_GOOS.h" -#include "os_GOOS.h" - -extern void runtime·sigtramp(void); - -typedef struct sigaction { - union { - void (*__sa_handler)(int32); - void (*__sa_sigaction)(int32, Siginfo*, void *); - } __sigaction_u; /* signal handler */ - uint32 sa_mask; /* signal mask to apply */ - int32 sa_flags; /* see signal options below */ -} Sigaction; - -void -runtime·dumpregs(Sigcontext *r) -{ - runtime·printf("rax %X\n", r->sc_rax); - runtime·printf("rbx %X\n", r->sc_rbx); - runtime·printf("rcx %X\n", r->sc_rcx); - runtime·printf("rdx %X\n", r->sc_rdx); - runtime·printf("rdi %X\n", r->sc_rdi); - runtime·printf("rsi %X\n", r->sc_rsi); - runtime·printf("rbp %X\n", r->sc_rbp); - runtime·printf("rsp %X\n", r->sc_rsp); - runtime·printf("r8 %X\n", r->sc_r8); - runtime·printf("r9 %X\n", r->sc_r9); - runtime·printf("r10 %X\n", r->sc_r10); - runtime·printf("r11 %X\n", r->sc_r11); - runtime·printf("r12 %X\n", r->sc_r12); - runtime·printf("r13 %X\n", r->sc_r13); - runtime·printf("r14 %X\n", r->sc_r14); - runtime·printf("r15 %X\n", r->sc_r15); - runtime·printf("rip %X\n", r->sc_rip); - runtime·printf("rflags %X\n", r->sc_rflags); - runtime·printf("cs %X\n", r->sc_cs); - runtime·printf("fs %X\n", r->sc_fs); - runtime·printf("gs %X\n", r->sc_gs); -} - -void -runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) -{ - Sigcontext *r = context; - uintptr *sp; - SigTab *t; - - if(sig == SIGPROF) { - runtime·sigprof((uint8*)r->sc_rip, - (uint8*)r->sc_rsp, nil, gp); - return; - } - - t = &runtime·sigtab[sig]; - if(info->si_code != SI_USER && (t->flags & SigPanic)) { - if(gp == nil || gp == m->g0) - goto Throw; - // 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*)((byte*)info + 16); /* si_addr */ - gp->sigpc = r->sc_rip; - - // Only push runtime·sigpanic if r->sc_rip != 0. - // If r->sc_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->sc_rip != 0) { - sp = (uintptr*)r->sc_rsp; - *--sp = r->sc_rip; - r->sc_rsp = (uintptr)sp; - } - r->sc_rip = (uintptr)runtime·sigpanic; - return; - } - - if(info->si_code == SI_USER || (t->flags & SigNotify)) - if(runtime·sigsend(sig)) - return; - if(t->flags & SigKill) - runtime·exit(2); - if(!(t->flags & SigThrow)) - return; - -Throw: - runtime·startpanic(); - - 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->sc_rip); - if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback()){ - runtime·traceback((void*)r->sc_rip, (void*)r->sc_rsp, 0, gp); - runtime·tracebackothers(gp); - runtime·dumpregs(r); - } - - runtime·exit(2); -} - -void -runtime·signalstack(byte *p, int32 n) -{ - Sigaltstack st; - - st.ss_sp = p; - st.ss_size = n; - st.ss_flags = 0; - if(p == nil) - st.ss_flags = SS_DISABLE; - runtime·sigaltstack(&st, nil); -} - -void -runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) -{ - Sigaction sa; - - // If SIGHUP handler is SIG_IGN, assume running - // under nohup and do not set explicit handler. - if(i == SIGHUP) { - runtime·memclr((byte*)&sa, sizeof sa); - runtime·sigaction(i, nil, &sa); - if(sa.__sigaction_u.__sa_sigaction == SIG_IGN) - return; - } - - runtime·memclr((byte*)&sa, sizeof sa); - sa.sa_flags = SA_SIGINFO|SA_ONSTACK; - if(restart) - sa.sa_flags |= SA_RESTART; - sa.sa_mask = ~0U; - if(fn == runtime·sighandler) - fn = (void*)runtime·sigtramp; - sa.__sigaction_u.__sa_sigaction = (void*)fn; - runtime·sigaction(i, &sa, nil); -} diff --git a/src/pkg/runtime/signal_openbsd_amd64.h b/src/pkg/runtime/signal_openbsd_amd64.h new file mode 100644 index 0000000000..b46a5dfa66 --- /dev/null +++ b/src/pkg/runtime/signal_openbsd_amd64.h @@ -0,0 +1,31 @@ +// Copyright 2013 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_REGS(ctxt) (*(Sigcontext*)(ctxt)) + +#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).sc_rax) +#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).sc_rbx) +#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).sc_rcx) +#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).sc_rdx) +#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).sc_rdi) +#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).sc_rsi) +#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).sc_rbp) +#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).sc_rsp) +#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).sc_r8) +#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).sc_r9) +#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).sc_r10) +#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).sc_r11) +#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).sc_r12) +#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).sc_r13) +#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).sc_r14) +#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).sc_r15) +#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).sc_rip) +#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).sc_rflags) + +#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).sc_cs) +#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).sc_fs) +#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).sc_gs) + +#define SIG_CODE0(info, ctxt) ((info)->si_code) +#define SIG_CODE1(info, ctxt) (*(uintptr*)((byte*)(info) + 16)) diff --git a/src/pkg/runtime/signal_plan9_386.c b/src/pkg/runtime/signal_plan9_386.c deleted file mode 100644 index 17bc117496..0000000000 --- a/src/pkg/runtime/signal_plan9_386.c +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2010 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_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "signals_GOOS.h" - -void -runtime·dumpregs(Ureg *u) -{ - runtime·printf("ax %X\n", u->ax); - runtime·printf("bx %X\n", u->bx); - runtime·printf("cx %X\n", u->cx); - runtime·printf("dx %X\n", u->dx); - runtime·printf("di %X\n", u->di); - runtime·printf("si %X\n", u->si); - runtime·printf("bp %X\n", u->bp); - runtime·printf("sp %X\n", u->sp); - runtime·printf("pc %X\n", u->pc); - runtime·printf("flags %X\n", u->flags); - runtime·printf("cs %X\n", u->cs); - runtime·printf("fs %X\n", u->fs); - runtime·printf("gs %X\n", u->gs); -} - -int32 -runtime·sighandler(void *v, int8 *s, G *gp) -{ - Ureg *ureg; - uintptr *sp; - SigTab *sig, *nsig; - int32 len, i; - - if(!s) - return NCONT; - - len = runtime·findnull((byte*)s); - if(len <= 4 || runtime·mcmp((byte*)s, (byte*)"sys:", 4) != 0) - return NDFLT; - - nsig = nil; - sig = runtime·sigtab; - for(i=0; i < NSIG; i++) { - if(runtime·strstr((byte*)s, (byte*)sig->name)) { - nsig = sig; - break; - } - sig++; - } - - if(nsig == nil) - return NDFLT; - - ureg = v; - if(nsig->flags & SigPanic) { - if(gp == nil || m->notesig == 0) - goto Throw; - - // Save error string from sigtramp's stack, - // into gsignal->sigcode0, so we can reliably - // access it from the panic routines. - if(len > ERRMAX) - len = ERRMAX; - runtime·memmove((void*)m->notesig, (void*)s, len); - - gp->sig = i; - gp->sigpc = ureg->pc; - - // Only push runtime·sigpanic if ureg->pc != 0. - // If ureg->pc == 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(ureg->pc != 0) { - sp = (uintptr*)ureg->sp; - *--sp = ureg->pc; - ureg->sp = (uint32)sp; - } - ureg->pc = (uintptr)runtime·sigpanic; - return NCONT; - } - - if(!(nsig->flags & SigThrow)) - return NDFLT; - -Throw: - runtime·startpanic(); - - runtime·printf("%s\n", s); - runtime·printf("PC=%X\n", ureg->pc); - runtime·printf("\n"); - - if(runtime·gotraceback()) { - runtime·traceback((void*)ureg->pc, (void*)ureg->sp, 0, gp); - runtime·tracebackothers(gp); - runtime·dumpregs(ureg); - } - runtime·goexitsall(""); - runtime·exits(s); - - return 0; -} - - -void -runtime·sigenable(uint32 sig) -{ - USED(sig); -} - -void -runtime·resetcpuprofiler(int32 hz) -{ - // TODO: Enable profiling interrupts. - - m->profilehz = hz; -} diff --git a/src/pkg/runtime/signal_plan9_amd64.c b/src/pkg/runtime/signal_plan9_amd64.c deleted file mode 100644 index e4f946abce..0000000000 --- a/src/pkg/runtime/signal_plan9_amd64.c +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2010 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_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "signals_GOOS.h" - -void -runtime·dumpregs(Ureg *u) -{ - runtime·printf("ax %X\n", u->ax); - runtime·printf("bx %X\n", u->bx); - runtime·printf("cx %X\n", u->cx); - runtime·printf("dx %X\n", u->dx); - runtime·printf("di %X\n", u->di); - runtime·printf("si %X\n", u->si); - runtime·printf("bp %X\n", u->bp); - runtime·printf("sp %X\n", u->sp); - runtime·printf("r8 %X\n", u->r8); - runtime·printf("r9 %X\n", u->r9); - runtime·printf("r10 %X\n", u->r10); - runtime·printf("r11 %X\n", u->r11); - runtime·printf("r12 %X\n", u->r12); - runtime·printf("r13 %X\n", u->r13); - runtime·printf("r14 %X\n", u->r14); - runtime·printf("r15 %X\n", u->r15); - runtime·printf("ip %X\n", u->ip); - runtime·printf("flags %X\n", u->flags); - runtime·printf("cs %X\n", (uint64)u->cs); - runtime·printf("fs %X\n", (uint64)u->fs); - runtime·printf("gs %X\n", (uint64)u->gs); -} - -int32 -runtime·sighandler(void *v, int8 *s, G *gp) -{ - Ureg *ureg; - uintptr *sp; - SigTab *sig, *nsig; - int32 len, i; - - if(!s) - return NCONT; - - len = runtime·findnull((byte*)s); - if(len <= 4 || runtime·mcmp((byte*)s, (byte*)"sys:", 4) != 0) - return NDFLT; - - nsig = nil; - sig = runtime·sigtab; - for(i=0; i < NSIG; i++) { - if(runtime·strstr((byte*)s, (byte*)sig->name)) { - nsig = sig; - break; - } - sig++; - } - - if(nsig == nil) - return NDFLT; - - ureg = v; - if(nsig->flags & SigPanic) { - if(gp == nil || m->notesig == 0) - goto Throw; - - // Save error string from sigtramp's stack, - // into gsignal->sigcode0, so we can reliably - // access it from the panic routines. - if(len > ERRMAX) - len = ERRMAX; - runtime·memmove((void*)m->notesig, (void*)s, len); - - gp->sig = i; - gp->sigpc = ureg->ip; - - // Only push runtime·sigpanic if ureg->ip != 0. - // If ureg->ip == 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(ureg->ip != 0) { - sp = (uintptr*)ureg->sp; - *--sp = ureg->ip; - ureg->sp = (uint64)sp; - } - ureg->ip = (uintptr)runtime·sigpanic; - return NCONT; - } - - if(!(nsig->flags & SigThrow)) - return NDFLT; - -Throw: - runtime·startpanic(); - - runtime·printf("%s\n", s); - runtime·printf("PC=%X\n", ureg->ip); - runtime·printf("\n"); - - if(runtime·gotraceback()) { - runtime·traceback((void*)ureg->ip, (void*)ureg->sp, 0, gp); - runtime·tracebackothers(gp); - runtime·dumpregs(ureg); - } - runtime·goexitsall(""); - runtime·exits(s); - - return 0; -} - -void -runtime·sigenable(uint32 sig) -{ - USED(sig); -} - -void -runtime·resetcpuprofiler(int32 hz) -{ - // TODO: Enable profiling interrupts. - - m->profilehz = hz; -} diff --git a/src/pkg/runtime/signal_unix.c b/src/pkg/runtime/signal_unix.c index 9b7e8b03a8..f3542acbae 100644 --- a/src/pkg/runtime/signal_unix.c +++ b/src/pkg/runtime/signal_unix.c @@ -7,6 +7,7 @@ #include "runtime.h" #include "defs_GOOS_GOARCH.h" #include "os_GOOS.h" +#include "signal_unix.h" extern SigTab runtime·sigtab[]; diff --git a/src/pkg/runtime/signal_unix.h b/src/pkg/runtime/signal_unix.h new file mode 100644 index 0000000000..a4acff4b20 --- /dev/null +++ b/src/pkg/runtime/signal_unix.h @@ -0,0 +1,13 @@ +// Copyright 2013 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) + +typedef void GoSighandler(int32, Siginfo*, void*, G*); +void runtime·setsig(int32, GoSighandler*, bool); +GoSighandler* runtime·getsig(int32); + +void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp); +void runtime·raisesigpipe(void); diff --git a/src/pkg/runtime/signal_windows_386.c b/src/pkg/runtime/signal_windows_386.c deleted file mode 100644 index d76d5bf4bd..0000000000 --- a/src/pkg/runtime/signal_windows_386.c +++ /dev/null @@ -1,97 +0,0 @@ -// 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_GOOS_GOARCH.h" -#include "os_GOOS.h" - -void -runtime·dumpregs(Context *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->SegCs); - runtime·printf("fs %x\n", r->SegFs); - runtime·printf("gs %x\n", r->SegGs); -} - -uint32 -runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) -{ - uintptr *sp; - - switch(info->ExceptionCode) { - case EXCEPTION_BREAKPOINT: - r->Eip--; // because 8l generates 2 bytes for INT3 - return 1; - } - - if(gp != nil && runtime·issigpanic(info->ExceptionCode)) { - // 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 = info->ExceptionCode; - gp->sigcode0 = info->ExceptionInformation[0]; - gp->sigcode1 = info->ExceptionInformation[1]; - 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 0; - } - - if(runtime·panicking) // traceback already printed - runtime·exit(2); - runtime·panicking = 1; - - runtime·printf("Exception %x %p %p\n", info->ExceptionCode, - info->ExceptionInformation[0], info->ExceptionInformation[1]); - - runtime·printf("PC=%x\n", r->Eip); - if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = m->lockedg; - } - 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); - return 0; -} - -void -runtime·sigenable(uint32 sig) -{ - USED(sig); -} - -void -runtime·dosigprof(Context *r, G *gp) -{ - runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp); -} diff --git a/src/pkg/runtime/signal_windows_amd64.c b/src/pkg/runtime/signal_windows_amd64.c deleted file mode 100644 index 3729aa57b7..0000000000 --- a/src/pkg/runtime/signal_windows_amd64.c +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2011 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_GOOS_GOARCH.h" -#include "os_GOOS.h" - -void -runtime·dumpregs(Context *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->EFlags); - runtime·printf("cs %X\n", (uint64)r->SegCs); - runtime·printf("fs %X\n", (uint64)r->SegFs); - runtime·printf("gs %X\n", (uint64)r->SegGs); -} - -uint32 -runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) -{ - uintptr *sp; - - switch(info->ExceptionCode) { - case EXCEPTION_BREAKPOINT: - return 1; - } - - if(gp != nil && runtime·issigpanic(info->ExceptionCode)) { - // 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 = info->ExceptionCode; - gp->sigcode0 = info->ExceptionInformation[0]; - gp->sigcode1 = info->ExceptionInformation[1]; - 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 0; - } - - if(runtime·panicking) // traceback already printed - runtime·exit(2); - runtime·panicking = 1; - - runtime·printf("Exception %x %p %p\n", info->ExceptionCode, - info->ExceptionInformation[0], info->ExceptionInformation[1]); - - runtime·printf("PC=%X\n", r->Rip); - if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = m->lockedg; - } - 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); - return 0; -} - -void -runtime·sigenable(uint32 sig) -{ - USED(sig); -} - -void -runtime·dosigprof(Context *r, G *gp) -{ - runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp); -} diff --git a/src/pkg/runtime/thread_darwin.c b/src/pkg/runtime/thread_darwin.c deleted file mode 100644 index 4394cbcdfd..0000000000 --- a/src/pkg/runtime/thread_darwin.c +++ /dev/null @@ -1,548 +0,0 @@ -// 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_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "stack.h" - -extern SigTab runtime·sigtab[]; - -static Sigset sigset_none; -static Sigset sigset_all = ~(Sigset)0; -static Sigset sigset_prof = 1<<(SIGPROF-1); - -static void -unimplemented(int8 *name) -{ - runtime·prints(name); - runtime·prints(" not implemented\n"); - *(int32*)1231 = 1231; -} - -int32 -runtime·semasleep(int64 ns) -{ - int32 v; - - if(m->profilehz > 0) - runtime·setprof(false); - v = runtime·mach_semacquire(m->waitsema, ns); - if(m->profilehz > 0) - runtime·setprof(true); - return v; -} - -void -runtime·semawakeup(M *mp) -{ - runtime·mach_semrelease(mp->waitsema); -} - -uintptr -runtime·semacreate(void) -{ - return runtime·mach_semcreate(); -} - -// BSD interface for threading. -void -runtime·osinit(void) -{ - // bsdthread_register delayed until end of goenvs so that we - // can look at the environment first. - - // Use sysctl to fetch hw.ncpu. - uint32 mib[2]; - uint32 out; - int32 ret; - uintptr nout; - - mib[0] = 6; - mib[1] = 3; - nout = sizeof out; - out = 0; - ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0); - if(ret >= 0) - runtime·ncpu = out; -} - -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - static byte urandom_data[HashRandomBytes]; - int32 fd; - fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0); - if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) { - *rnd = urandom_data; - *rnd_len = HashRandomBytes; - } else { - *rnd = nil; - *rnd_len = 0; - } - runtime·close(fd); -} - -void -runtime·goenvs(void) -{ - runtime·goenvs_unix(); - - // Register our thread-creation callback (see sys_darwin_{amd64,386}.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) { - if(runtime·bsdthread_register() != 0) { - if(runtime·getenv("DYLD_INSERT_LIBRARIES")) - runtime·throw("runtime: bsdthread_register error (unset DYLD_INSERT_LIBRARIES)"); - runtime·throw("runtime: bsdthread_register error"); - } - } - -} - -void -runtime·newosproc(M *mp, void *stk) -{ - int32 errno; - Sigset oset; - - mp->tls[0] = mp->id; // so 386 asm can find it - if(0){ - runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n", - stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp); - } - - runtime·sigprocmask(SIG_SETMASK, &sigset_all, &oset); - errno = runtime·bsdthread_create(stk, mp, mp->g0, runtime·mstart); - runtime·sigprocmask(SIG_SETMASK, &oset, nil); - - if(errno < 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). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - mp->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - // Initialize signal handling. - runtime·signalstack((byte*)m->gsignal->stackguard - StackGuard, 32*1024); - - runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); - runtime·setprof(m->profilehz > 0); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ - runtime·signalstack(nil, 0); -} - -// 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; imsgh_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; imsgh_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, - KERN_OPERATION_TIMED_OUT = 49, -}; - -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_darwin_{amd64,386}.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); - -int32 -runtime·mach_semacquire(uint32 sem, int64 ns) -{ - int32 r; - - if(ns >= 0) { - r = runtime·mach_semaphore_timedwait(sem, ns/1000000000LL, ns%1000000000LL); - if(r == KERN_ABORTED || r == KERN_OPERATION_TIMED_OUT) - return -1; - if(r != 0) - macherror(r, "semaphore_wait"); - return 0; - } - while((r = runtime·mach_semaphore_wait(sem)) != 0) { - if(r == KERN_ABORTED) // interrupted - continue; - macherror(r, "semaphore_wait"); - } - return 0; -} - -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) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - 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) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - 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); -} - -#pragma textflag 7 -void -runtime·osyield(void) -{ - runtime·usleep(1); -} - -uintptr -runtime·memlimit(void) -{ - // NOTE(rsc): Could use getrlimit here, - // like on FreeBSD or Linux, but Darwin doesn't enforce - // ulimit -v, so it's unclear why we'd try to stay within - // the limit. - return 0; -} - -// NOTE(rsc): On OS X, when the CPU profiling timer expires, the SIGPROF -// signal is not guaranteed to be sent to the thread that was executing to -// cause it to expire. It can and often does go to a sleeping thread, which is -// not interesting for our profile. This is filed Apple Bug Report #9177434, -// copied to http://code.google.com/p/go/source/detail?r=35b716c94225. -// To work around this bug, we disable receipt of the profiling signal on -// a thread while in blocking system calls. This forces the kernel to deliver -// the profiling signal to an executing thread. -// -// The workaround fails on OS X machines using a 64-bit Snow Leopard kernel. -// In that configuration, the kernel appears to want to deliver SIGPROF to the -// sleeping threads regardless of signal mask and, worse, does not deliver -// the signal until the thread wakes up on its own. -// -// If necessary, we can switch to using ITIMER_REAL for OS X and handle -// the kernel-generated SIGALRM by generating our own SIGALRMs to deliver -// to all the running threads. SIGALRM does not appear to be affected by -// the 64-bit Snow Leopard bug. However, as of this writing Mountain Lion -// is in preview, making Snow Leopard two versions old, so it is unclear how -// much effort we need to spend on one buggy kernel. - -// Control whether profiling signal can be delivered to this thread. -void -runtime·setprof(bool on) -{ - if(on) - runtime·sigprocmask(SIG_UNBLOCK, &sigset_prof, nil); - else - runtime·sigprocmask(SIG_BLOCK, &sigset_prof, nil); -} - -static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n"; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag 7 -void -runtime·badcallback(void) -{ - runtime·write(2, badcallback, sizeof badcallback - 1); -} - -static int8 badsignal[] = "runtime: signal received on thread not created by Go: "; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag 7 -void -runtime·badsignal(int32 sig) -{ - if (sig == SIGPROF) { - return; // Ignore SIGPROFs intended for a non-Go thread. - } - runtime·write(2, badsignal, sizeof badsignal - 1); - if (0 <= sig && sig < NSIG) { - // Call runtime·findnull dynamically to circumvent static stack size check. - static int32 (*findnull)(byte*) = runtime·findnull; - runtime·write(2, runtime·sigtab[sig].name, findnull((byte*)runtime·sigtab[sig].name)); - } - runtime·write(2, "\n", 1); - runtime·exit(1); -} diff --git a/src/pkg/runtime/thread_freebsd.c b/src/pkg/runtime/thread_freebsd.c deleted file mode 100644 index 7ead04468f..0000000000 --- a/src/pkg/runtime/thread_freebsd.c +++ /dev/null @@ -1,259 +0,0 @@ -// Use of this source file is governed by a BSD-style -// license that can be found in the LICENSE file.` - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "stack.h" - -extern SigTab runtime·sigtab[]; -extern int32 runtime·sys_umtx_op(uint32*, int32, uint32, void*, void*); - -// From FreeBSD's -#define CTL_HW 6 -#define HW_NCPU 3 - -static Sigset sigset_none; -static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, }; - -static int32 -getncpu(void) -{ - uint32 mib[2]; - uint32 out; - int32 ret; - uintptr nout; - - // Fetch hw.ncpu via sysctl. - mib[0] = CTL_HW; - mib[1] = HW_NCPU; - nout = sizeof out; - out = 0; - ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0); - if(ret >= 0) - return out; - else - return 1; -} - -// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and -// thus the code is largely similar. See linux/thread.c and lock_futex.c for comments. - -void -runtime·futexsleep(uint32 *addr, uint32 val, int64 ns) -{ - int32 ret; - Timespec ts, *tsp; - - if(ns < 0) - tsp = nil; - else { - ts.tv_sec = ns / 1000000000LL; - ts.tv_nsec = ns % 1000000000LL; - tsp = &ts; - } - - ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT, val, nil, tsp); - if(ret >= 0 || ret == -EINTR) - return; - - runtime·printf("umtx_wait addr=%p val=%d ret=%d\n", addr, val, ret); - *(int32*)0x1005 = 0x1005; -} - -void -runtime·futexwakeup(uint32 *addr, uint32 cnt) -{ - int32 ret; - - ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE, cnt, nil, nil); - if(ret >= 0) - return; - - runtime·printf("umtx_wake addr=%p ret=%d\n", addr, ret); - *(int32*)0x1006 = 0x1006; -} - -void runtime·thr_start(void*); - -void -runtime·newosproc(M *mp, void *stk) -{ - ThrParam param; - Sigset oset; - - if(0){ - runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n", - stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp); - } - - runtime·sigprocmask(&sigset_all, &oset); - runtime·memclr((byte*)¶m, sizeof param); - - param.start_func = runtime·thr_start; - param.arg = (byte*)mp; - - // NOTE(rsc): This code is confused. stackbase is the top of the stack - // and is equal to stk. However, it's working, so I'm not changing it. - param.stack_base = (void*)mp->g0->stackbase; - param.stack_size = (byte*)stk - (byte*)mp->g0->stackbase; - - param.child_tid = (intptr*)&mp->procid; - param.parent_tid = nil; - param.tls_base = (void*)&mp->tls[0]; - param.tls_size = sizeof mp->tls; - - mp->tls[0] = mp->id; // so 386 asm can find it - - runtime·thr_new(¶m, sizeof param); - runtime·sigprocmask(&oset, nil); -} - -void -runtime·osinit(void) -{ - runtime·ncpu = getncpu(); -} - -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - static byte urandom_data[HashRandomBytes]; - int32 fd; - fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0); - if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) { - *rnd = urandom_data; - *rnd_len = HashRandomBytes; - } else { - *rnd = nil; - *rnd_len = 0; - } - runtime·close(fd); -} - -void -runtime·goenvs(void) -{ - runtime·goenvs_unix(); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - mp->gsignal = runtime·malg(32*1024); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - // Initialize signal handling - runtime·signalstack((byte*)m->gsignal->stackguard - StackGuard, 32*1024); - runtime·sigprocmask(&sigset_none, nil); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ - runtime·signalstack(nil, 0); -} - -void -runtime·sigpanic(void) -{ - switch(g->sig) { - case SIGBUS: - if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - 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) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - 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); -} - -uintptr -runtime·memlimit(void) -{ - Rlimit rl; - extern byte text[], end[]; - uintptr used; - - if(runtime·getrlimit(RLIMIT_AS, &rl) != 0) - return 0; - if(rl.rlim_cur >= 0x7fffffff) - return 0; - - // Estimate our VM footprint excluding the heap. - // Not an exact science: use size of binary plus - // some room for thread stacks. - used = end - text + (64<<20); - if(used >= rl.rlim_cur) - return 0; - - // If there's not at least 16 MB left, we're probably - // not going to be able to do much. Treat as no limit. - rl.rlim_cur -= used; - if(rl.rlim_cur < (16<<20)) - return 0; - - return rl.rlim_cur - used; -} - -void -runtime·setprof(bool on) -{ - USED(on); -} - -static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n"; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag 7 -void -runtime·badcallback(void) -{ - runtime·write(2, badcallback, sizeof badcallback - 1); -} - -static int8 badsignal[] = "runtime: signal received on thread not created by Go: "; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag 7 -void -runtime·badsignal(int32 sig) -{ - if (sig == SIGPROF) { - return; // Ignore SIGPROFs intended for a non-Go thread. - } - runtime·write(2, badsignal, sizeof badsignal - 1); - if (0 <= sig && sig < NSIG) { - // Call runtime·findnull dynamically to circumvent static stack size check. - static int32 (*findnull)(byte*) = runtime·findnull; - runtime·write(2, runtime·sigtab[sig].name, findnull((byte*)runtime·sigtab[sig].name)); - } - runtime·write(2, "\n", 1); - runtime·exit(1); -} diff --git a/src/pkg/runtime/thread_linux.c b/src/pkg/runtime/thread_linux.c deleted file mode 100644 index 7fdc757dfc..0000000000 --- a/src/pkg/runtime/thread_linux.c +++ /dev/null @@ -1,311 +0,0 @@ -// 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_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "stack.h" - -extern SigTab runtime·sigtab[]; - -static Sigset sigset_none; -static Sigset sigset_all = { ~(uint32)0, ~(uint32)0 }; - -// Linux futex. -// -// futexsleep(uint32 *addr, uint32 val) -// futexwakeup(uint32 *addr) -// -// Futexsleep atomically checks if *addr == val and if so, sleeps on addr. -// Futexwakeup wakes up threads sleeping on addr. -// Futexsleep is allowed to wake up spuriously. - -enum -{ - FUTEX_WAIT = 0, - FUTEX_WAKE = 1, -}; - -// Atomically, -// if(*addr == val) sleep -// Might be woken up spuriously; that's allowed. -// Don't sleep longer than ns; ns < 0 means forever. -void -runtime·futexsleep(uint32 *addr, uint32 val, int64 ns) -{ - Timespec ts, *tsp; - - if(ns < 0) - tsp = nil; - else { - ts.tv_sec = ns/1000000000LL; - ts.tv_nsec = ns%1000000000LL; - // Avoid overflow - if(ts.tv_sec > 1<<30) - ts.tv_sec = 1<<30; - tsp = &ts; - } - - // Some Linux kernels have a bug where futex of - // FUTEX_WAIT returns an internal error code - // as an errno. Libpthread ignores the return value - // here, and so can we: as it says a few lines up, - // spurious wakeups are allowed. - runtime·futex(addr, FUTEX_WAIT, val, tsp, nil, 0); -} - -// If any procs are sleeping on addr, wake up at most cnt. -void -runtime·futexwakeup(uint32 *addr, uint32 cnt) -{ - int64 ret; - - ret = runtime·futex(addr, FUTEX_WAKE, cnt, nil, nil, 0); - - if(ret >= 0) - return; - - // I don't know that futex wakeup can return - // EAGAIN or EINTR, but if it does, it would be - // safe to loop and call futex again. - runtime·printf("futexwakeup addr=%p returned %D\n", addr, ret); - *(int32*)0x1006 = 0x1006; -} - -extern runtime·sched_getaffinity(uintptr pid, uintptr len, uintptr *buf); -static int32 -getproccount(void) -{ - uintptr buf[16], t; - int32 r, cnt, i; - - cnt = 0; - r = runtime·sched_getaffinity(0, sizeof(buf), buf); - if(r > 0) - for(i = 0; i < r/sizeof(buf[0]); i++) { - t = buf[i]; - t = t - ((t >> 1) & 0x5555555555555555ULL); - t = (t & 0x3333333333333333ULL) + ((t >> 2) & 0x3333333333333333ULL); - cnt += (int32)((((t + (t >> 4)) & 0xF0F0F0F0F0F0F0FULL) * 0x101010101010101ULL) >> 56); - } - - return cnt ? cnt : 1; -} - -// Clone, the Linux rfork. -enum -{ - CLONE_VM = 0x100, - CLONE_FS = 0x200, - CLONE_FILES = 0x400, - CLONE_SIGHAND = 0x800, - CLONE_PTRACE = 0x2000, - CLONE_VFORK = 0x4000, - CLONE_PARENT = 0x8000, - CLONE_THREAD = 0x10000, - CLONE_NEWNS = 0x20000, - CLONE_SYSVSEM = 0x40000, - CLONE_SETTLS = 0x80000, - CLONE_PARENT_SETTID = 0x100000, - CLONE_CHILD_CLEARTID = 0x200000, - CLONE_UNTRACED = 0x800000, - CLONE_CHILD_SETTID = 0x1000000, - CLONE_STOPPED = 0x2000000, - CLONE_NEWUTS = 0x4000000, - CLONE_NEWIPC = 0x8000000, -}; - -void -runtime·newosproc(M *mp, void *stk) -{ - int32 ret; - int32 flags; - Sigset oset; - - /* - * note: strace gets confused if we use CLONE_PTRACE here. - */ - flags = CLONE_VM /* share memory */ - | CLONE_FS /* share cwd, etc */ - | CLONE_FILES /* share fd table */ - | CLONE_SIGHAND /* share sig handler table */ - | CLONE_THREAD /* revisit - okay for now */ - ; - - mp->tls[0] = mp->id; // so 386 asm can find it - if(0){ - runtime·printf("newosproc stk=%p m=%p g=%p clone=%p id=%d/%d ostk=%p\n", - stk, mp, mp->g0, runtime·clone, mp->id, (int32)mp->tls[0], &mp); - } - - // Disable signals during clone, so that the new thread starts - // with signals disabled. It will enable them in minit. - runtime·rtsigprocmask(SIG_SETMASK, &sigset_all, &oset, sizeof oset); - ret = runtime·clone(flags, stk, mp, mp->g0, runtime·mstart); - runtime·rtsigprocmask(SIG_SETMASK, &oset, nil, sizeof oset); - - if(ret < 0) { - runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), -ret); - runtime·throw("runtime.newosproc"); - } -} - -void -runtime·osinit(void) -{ - runtime·ncpu = getproccount(); -} - -// Random bytes initialized at startup. These come -// from the ELF AT_RANDOM auxiliary vector (vdso_linux_amd64.c). -byte* runtime·startup_random_data; -uint32 runtime·startup_random_data_len; - -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - if(runtime·startup_random_data != nil) { - *rnd = runtime·startup_random_data; - *rnd_len = runtime·startup_random_data_len; - } else { - static byte urandom_data[HashRandomBytes]; - int32 fd; - fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0); - if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) { - *rnd = urandom_data; - *rnd_len = HashRandomBytes; - } else { - *rnd = nil; - *rnd_len = 0; - } - runtime·close(fd); - } -} - -void -runtime·goenvs(void) -{ - runtime·goenvs_unix(); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - mp->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - // Initialize signal handling. - runtime·signalstack((byte*)m->gsignal->stackguard - StackGuard, 32*1024); - runtime·rtsigprocmask(SIG_SETMASK, &sigset_none, nil, sizeof(Sigset)); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ - runtime·signalstack(nil, 0); -} - -void -runtime·sigpanic(void) -{ - switch(g->sig) { - case SIGBUS: - if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - } - 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) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - 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); -} - -uintptr -runtime·memlimit(void) -{ - Rlimit rl; - extern byte text[], end[]; - uintptr used; - - if(runtime·getrlimit(RLIMIT_AS, &rl) != 0) - return 0; - if(rl.rlim_cur >= 0x7fffffff) - return 0; - - // Estimate our VM footprint excluding the heap. - // Not an exact science: use size of binary plus - // some room for thread stacks. - used = end - text + (64<<20); - if(used >= rl.rlim_cur) - return 0; - - // If there's not at least 16 MB left, we're probably - // not going to be able to do much. Treat as no limit. - rl.rlim_cur -= used; - if(rl.rlim_cur < (16<<20)) - return 0; - - return rl.rlim_cur - used; -} - -void -runtime·setprof(bool on) -{ - USED(on); -} - -static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n"; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag 7 -void -runtime·badcallback(void) -{ - runtime·write(2, badcallback, sizeof badcallback - 1); -} - -static int8 badsignal[] = "runtime: signal received on thread not created by Go: "; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag 7 -void -runtime·badsignal(int32 sig) -{ - if (sig == SIGPROF) { - return; // Ignore SIGPROFs intended for a non-Go thread. - } - runtime·write(2, badsignal, sizeof badsignal - 1); - if (0 <= sig && sig < NSIG) { - // Call runtime·findnull dynamically to circumvent static stack size check. - static int32 (*findnull)(byte*) = runtime·findnull; - runtime·write(2, runtime·sigtab[sig].name, findnull((byte*)runtime·sigtab[sig].name)); - } - runtime·write(2, "\n", 1); - runtime·exit(1); -} diff --git a/src/pkg/runtime/thread_netbsd.c b/src/pkg/runtime/thread_netbsd.c deleted file mode 100644 index 58bc0a8a33..0000000000 --- a/src/pkg/runtime/thread_netbsd.c +++ /dev/null @@ -1,304 +0,0 @@ -// Use of this source file is governed by a BSD-style -// license that can be found in the LICENSE file.` - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "stack.h" - -enum -{ - ESRCH = 3, - ENOTSUP = 91, - - // From NetBSD's - CLOCK_REALTIME = 0, - CLOCK_VIRTUAL = 1, - CLOCK_PROF = 2, - CLOCK_MONOTONIC = 3 -}; - -extern SigTab runtime·sigtab[]; - -static Sigset sigset_none; -static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, }; - -extern void runtime·getcontext(UcontextT *context); -extern int32 runtime·lwp_create(UcontextT *context, uintptr flags, void *lwpid); -extern void runtime·lwp_mcontext_init(void *mc, void *stack, M *mp, G *gp, void (*fn)(void)); -extern int32 runtime·lwp_park(Timespec *abstime, int32 unpark, void *hint, void *unparkhint); -extern int32 runtime·lwp_unpark(int32 lwp, void *hint); -extern int32 runtime·lwp_self(void); - -// From NetBSD's -#define CTL_HW 6 -#define HW_NCPU 3 - -static int32 -getncpu(void) -{ - uint32 mib[2]; - uint32 out; - int32 ret; - uintptr nout; - - // Fetch hw.ncpu via sysctl. - mib[0] = CTL_HW; - mib[1] = HW_NCPU; - nout = sizeof out; - out = 0; - ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0); - if(ret >= 0) - return out; - else - return 1; -} - -uintptr -runtime·semacreate(void) -{ - return 1; -} - -int32 -runtime·semasleep(int64 ns) -{ - Timespec ts; - - // spin-mutex lock - while(runtime·xchg(&m->waitsemalock, 1)) - runtime·osyield(); - - for(;;) { - // lock held - if(m->waitsemacount == 0) { - // sleep until semaphore != 0 or timeout. - // thrsleep unlocks m->waitsemalock. - if(ns < 0) { - // TODO(jsing) - potential deadlock! - // - // There is a potential deadlock here since we - // have to release the waitsemalock mutex - // before we call lwp_park() to suspend the - // thread. This allows another thread to - // release the lock and call lwp_unpark() - // before the thread is actually suspended. - // If this occurs the current thread will end - // up sleeping indefinitely. Unfortunately - // the NetBSD kernel does not appear to provide - // a mechanism for unlocking the userspace - // mutex once the thread is actually parked. - runtime·atomicstore(&m->waitsemalock, 0); - runtime·lwp_park(nil, 0, &m->waitsemacount, nil); - } else { - ns += runtime·nanotime(); - ts.tv_sec = ns/1000000000LL; - ts.tv_nsec = ns%1000000000LL; - // TODO(jsing) - potential deadlock! - // See above for details. - runtime·atomicstore(&m->waitsemalock, 0); - runtime·lwp_park(&ts, 0, &m->waitsemacount, nil); - } - // reacquire lock - while(runtime·xchg(&m->waitsemalock, 1)) - runtime·osyield(); - } - - // lock held (again) - if(m->waitsemacount != 0) { - // semaphore is available. - m->waitsemacount--; - // spin-mutex unlock - runtime·atomicstore(&m->waitsemalock, 0); - return 0; // semaphore acquired - } - - // semaphore not available. - // if there is a timeout, stop now. - // otherwise keep trying. - if(ns >= 0) - break; - } - - // lock held but giving up - // spin-mutex unlock - runtime·atomicstore(&m->waitsemalock, 0); - return -1; -} - -void -runtime·semawakeup(M *mp) -{ - uint32 ret; - - // spin-mutex lock - while(runtime·xchg(&mp->waitsemalock, 1)) - runtime·osyield(); - mp->waitsemacount++; - // TODO(jsing) - potential deadlock, see semasleep() for details. - // Confirm that LWP is parked before unparking... - ret = runtime·lwp_unpark(mp->procid, &mp->waitsemacount); - if(ret != 0 && ret != ESRCH) - runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret); - // spin-mutex unlock - runtime·atomicstore(&mp->waitsemalock, 0); -} - -void -runtime·newosproc(M *mp, void *stk) -{ - UcontextT uc; - int32 ret; - - if(0) { - runtime·printf( - "newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n", - stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp); - } - - mp->tls[0] = mp->id; // so 386 asm can find it - - runtime·getcontext(&uc); - - uc.uc_flags = _UC_SIGMASK | _UC_CPU; - uc.uc_link = nil; - uc.uc_sigmask = sigset_all; - - runtime·lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp->g0, runtime·mstart); - - ret = runtime·lwp_create(&uc, 0, &mp->procid); - - if(ret < 0) { - runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret); - runtime·throw("runtime.newosproc"); - } -} - -void -runtime·osinit(void) -{ - runtime·ncpu = getncpu(); -} - -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - static byte urandom_data[HashRandomBytes]; - int32 fd; - fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0); - if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) { - *rnd = urandom_data; - *rnd_len = HashRandomBytes; - } else { - *rnd = nil; - *rnd_len = 0; - } - runtime·close(fd); -} - -void -runtime·goenvs(void) -{ - runtime·goenvs_unix(); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - mp->gsignal = runtime·malg(32*1024); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - m->procid = runtime·lwp_self(); - - // Initialize signal handling - runtime·signalstack((byte*)m->gsignal->stackguard - StackGuard, 32*1024); - runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ - runtime·signalstack(nil, 0); -} - -void -runtime·sigpanic(void) -{ - switch(g->sig) { - case SIGBUS: - if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - 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) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - 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); -} - -uintptr -runtime·memlimit(void) -{ - return 0; -} - -void -runtime·setprof(bool on) -{ - USED(on); -} - -static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n"; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag 7 -void -runtime·badcallback(void) -{ - runtime·write(2, badcallback, sizeof badcallback - 1); -} - -static int8 badsignal[] = "runtime: signal received on thread not created by Go: "; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag 7 -void -runtime·badsignal(int32 sig) -{ - if (sig == SIGPROF) { - return; // Ignore SIGPROFs intended for a non-Go thread. - } - runtime·write(2, badsignal, sizeof badsignal - 1); - if (0 <= sig && sig < NSIG) { - // Call runtime·findnull dynamically to circumvent static stack size check. - static int32 (*findnull)(byte*) = runtime·findnull; - runtime·write(2, runtime·sigtab[sig].name, findnull((byte*)runtime·sigtab[sig].name)); - } - runtime·write(2, "\n", 1); - runtime·exit(1); -} diff --git a/src/pkg/runtime/thread_openbsd.c b/src/pkg/runtime/thread_openbsd.c deleted file mode 100644 index f2d17404fd..0000000000 --- a/src/pkg/runtime/thread_openbsd.c +++ /dev/null @@ -1,281 +0,0 @@ -// Use of this source file is governed by a BSD-style -// license that can be found in the LICENSE file.` - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "stack.h" - -enum -{ - ESRCH = 3, - ENOTSUP = 91, - - // From OpenBSD's sys/time.h - CLOCK_REALTIME = 0, - CLOCK_VIRTUAL = 1, - CLOCK_PROF = 2, - CLOCK_MONOTONIC = 3 -}; - -extern SigTab runtime·sigtab[]; - -static Sigset sigset_none; -static Sigset sigset_all = ~(Sigset)0; - -extern int64 runtime·tfork(void *param, uintptr psize, M *mp, G *gp, void (*fn)(void)); -extern int32 runtime·thrsleep(void *ident, int32 clock_id, void *tsp, void *lock, const int32 *abort); -extern int32 runtime·thrwakeup(void *ident, int32 n); - -// From OpenBSD's -#define CTL_HW 6 -#define HW_NCPU 3 - -static int32 -getncpu(void) -{ - uint32 mib[2]; - uint32 out; - int32 ret; - uintptr nout; - - // Fetch hw.ncpu via sysctl. - mib[0] = CTL_HW; - mib[1] = HW_NCPU; - nout = sizeof out; - out = 0; - ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0); - if(ret >= 0) - return out; - else - return 1; -} - -uintptr -runtime·semacreate(void) -{ - return 1; -} - -int32 -runtime·semasleep(int64 ns) -{ - Timespec ts; - - // spin-mutex lock - while(runtime·xchg(&m->waitsemalock, 1)) - runtime·osyield(); - - for(;;) { - // lock held - if(m->waitsemacount == 0) { - // sleep until semaphore != 0 or timeout. - // thrsleep unlocks m->waitsemalock. - if(ns < 0) - runtime·thrsleep(&m->waitsemacount, 0, nil, &m->waitsemalock, nil); - else { - ns += runtime·nanotime(); - ts.tv_sec = ns/1000000000LL; - ts.tv_nsec = ns%1000000000LL; - runtime·thrsleep(&m->waitsemacount, CLOCK_REALTIME, &ts, &m->waitsemalock, nil); - } - // reacquire lock - while(runtime·xchg(&m->waitsemalock, 1)) - runtime·osyield(); - } - - // lock held (again) - if(m->waitsemacount != 0) { - // semaphore is available. - m->waitsemacount--; - // spin-mutex unlock - runtime·atomicstore(&m->waitsemalock, 0); - return 0; // semaphore acquired - } - - // semaphore not available. - // if there is a timeout, stop now. - // otherwise keep trying. - if(ns >= 0) - break; - } - - // lock held but giving up - // spin-mutex unlock - runtime·atomicstore(&m->waitsemalock, 0); - return -1; -} - -void -runtime·semawakeup(M *mp) -{ - uint32 ret; - - // spin-mutex lock - while(runtime·xchg(&mp->waitsemalock, 1)) - runtime·osyield(); - mp->waitsemacount++; - ret = runtime·thrwakeup(&mp->waitsemacount, 1); - if(ret != 0 && ret != ESRCH) - runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret); - // spin-mutex unlock - runtime·atomicstore(&mp->waitsemalock, 0); -} - -void -runtime·newosproc(M *mp, void *stk) -{ - Tfork param; - Sigset oset; - int32 ret; - - if(0) { - runtime·printf( - "newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n", - stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp); - } - - mp->tls[0] = mp->id; // so 386 asm can find it - - param.tf_tcb = (byte*)&mp->tls[0]; - param.tf_tid = (int32*)&mp->procid; - param.tf_stack = stk; - - oset = runtime·sigprocmask(SIG_SETMASK, sigset_all); - ret = runtime·tfork((byte*)¶m, sizeof(param), mp, mp->g0, runtime·mstart); - runtime·sigprocmask(SIG_SETMASK, oset); - - if(ret < 0) { - runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret); - if (ret == -ENOTSUP) - runtime·printf("runtime: is kern.rthreads disabled?\n"); - runtime·throw("runtime.newosproc"); - } -} - -void -runtime·osinit(void) -{ - runtime·ncpu = getncpu(); -} - -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - static byte urandom_data[HashRandomBytes]; - int32 fd; - fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0); - if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) { - *rnd = urandom_data; - *rnd_len = HashRandomBytes; - } else { - *rnd = nil; - *rnd_len = 0; - } - runtime·close(fd); -} - -void -runtime·goenvs(void) -{ - runtime·goenvs_unix(); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - mp->gsignal = runtime·malg(32*1024); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - // Initialize signal handling - runtime·signalstack((byte*)m->gsignal->stackguard - StackGuard, 32*1024); - runtime·sigprocmask(SIG_SETMASK, sigset_none); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ - runtime·signalstack(nil, 0); -} - -void -runtime·sigpanic(void) -{ - switch(g->sig) { - case SIGBUS: - if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - 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) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - 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); -} - -uintptr -runtime·memlimit(void) -{ - return 0; -} - -void -runtime·setprof(bool on) -{ - USED(on); -} - -static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n"; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag 7 -void -runtime·badcallback(void) -{ - runtime·write(2, badcallback, sizeof badcallback - 1); -} - -static int8 badsignal[] = "runtime: signal received on thread not created by Go: "; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag 7 -void -runtime·badsignal(int32 sig) -{ - if (sig == SIGPROF) { - return; // Ignore SIGPROFs intended for a non-Go thread. - } - runtime·write(2, badsignal, sizeof badsignal - 1); - if (0 <= sig && sig < NSIG) { - // Call runtime·findnull dynamically to circumvent static stack size check. - static int32 (*findnull)(byte*) = runtime·findnull; - runtime·write(2, runtime·sigtab[sig].name, findnull((byte*)runtime·sigtab[sig].name)); - } - runtime·write(2, "\n", 1); - runtime·exit(1); -} diff --git a/src/pkg/runtime/thread_plan9.c b/src/pkg/runtime/thread_plan9.c deleted file mode 100644 index 338da8f216..0000000000 --- a/src/pkg/runtime/thread_plan9.c +++ /dev/null @@ -1,344 +0,0 @@ -// Copyright 2010 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 "os_GOOS.h" -#include "arch_GOARCH.h" - -int8 *goos = "plan9"; -extern SigTab runtime·sigtab[]; - -int32 runtime·postnote(int32, int8*); - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - // Initialize stack and goroutine for note handling. - mp->gsignal = runtime·malg(32*1024); - mp->notesig = (int8*)runtime·malloc(ERRMAX*sizeof(int8)); - - // Initialize stack for handling strings from the - // errstr system call, as used in package syscall. - mp->errstr = (byte*)runtime·malloc(ERRMAX*sizeof(byte)); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - // Mask all SSE floating-point exceptions - // when running on the 64-bit kernel. - runtime·setfpmasks(); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ -} - - -static int32 -getproccount(void) -{ - int32 fd, i, n, ncpu; - byte buf[2048]; - - fd = runtime·open("/dev/sysstat", OREAD, 0); - if(fd < 0) - return 1; - ncpu = 0; - for(;;) { - n = runtime·read(fd, buf, sizeof buf); - if(n <= 0) - break; - for(i = 0; i < n; i++) { - if(buf[i] == '\n') - ncpu++; - } - } - runtime·close(fd); - return ncpu > 0 ? ncpu : 1; -} - -static int32 -getpid(void) -{ - byte b[20], *c; - int32 fd; - - runtime·memclr(b, sizeof(b)); - fd = runtime·open("#c/pid", 0, 0); - if(fd >= 0) { - runtime·read(fd, b, sizeof(b)); - runtime·close(fd); - } - c = b; - while(*c == ' ' || *c == '\t') - c++; - return runtime·atoi(c); -} - -void -runtime·osinit(void) -{ - runtime·ncpu = getproccount(); - m->procid = getpid(); - runtime·notify(runtime·sigtramp); -} - -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - *rnd = nil; - *rnd_len = 0; -} - -void -runtime·goenvs(void) -{ -} - -void -runtime·initsig(void) -{ -} - -#pragma textflag 7 -void -runtime·osyield(void) -{ - runtime·sleep(0); -} - -void -runtime·usleep(uint32 µs) -{ - uint32 ms; - - ms = µs/1000; - if(ms == 0) - ms = 1; - runtime·sleep(ms); -} - -void -time·now(int64 sec, int32 nsec) -{ - int64 ns; - - ns = runtime·nanotime(); - sec = ns / 1000000000LL; - nsec = ns - sec * 1000000000LL; - FLUSH(&sec); - FLUSH(&nsec); -} - -void -runtime·itoa(int32 n, byte *p, uint32 len) -{ - byte *q, c; - uint32 i; - - if(len <= 1) - return; - - runtime·memclr(p, len); - q = p; - - if(n==0) { - *q++ = '0'; - USED(q); - return; - } - if(n < 0) { - *q++ = '-'; - p++; - n = -n; - } - for(i=0; n > 0 && i < len; i++) { - *q++ = '0' + (n%10); - n = n/10; - } - for(q--; q >= p; ) { - c = *p; - *p++ = *q; - *q-- = c; - } -} - -void -runtime·goexitsall(int8 *status) -{ - M *mp; - int32 pid; - - pid = getpid(); - for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink) - if(mp->procid != pid) - runtime·postnote(mp->procid, status); -} - -int32 -runtime·postnote(int32 pid, int8* msg) -{ - int32 fd, len; - uint8 buf[128]; - uint8 tmp[16]; - uint8 *p, *q; - - runtime·memclr(buf, sizeof buf); - - /* build path string /proc/pid/note */ - q = tmp; - p = buf; - runtime·itoa(pid, tmp, sizeof tmp); - runtime·memmove((void*)p, (void*)"/proc/", 6); - for(p += 6; *p++ = *q++; ); - p--; - runtime·memmove((void*)p, (void*)"/note", 5); - - fd = runtime·open((int8*)buf, OWRITE, 0); - if(fd < 0) - return -1; - - len = runtime·findnull((byte*)msg); - if(runtime·write(fd, msg, len) != len) { - runtime·close(fd); - return -1; - } - runtime·close(fd); - return 0; -} - -void -runtime·exit(int32 e) -{ - byte tmp[16]; - int8 *status; - - if(e == 0) - status = ""; - else { - /* build error string */ - runtime·itoa(e, tmp, sizeof tmp); - status = (int8*)tmp; - } - - runtime·goexitsall(status); - runtime·exits(status); -} - -void -runtime·newosproc(M *mp, void *stk) -{ - mp->tls[0] = mp->id; // so 386 asm can find it - if(0){ - runtime·printf("newosproc stk=%p m=%p g=%p rfork=%p id=%d/%d ostk=%p\n", - stk, mp, mp->g0, runtime·rfork, mp->id, (int32)mp->tls[0], &mp); - } - - if(runtime·rfork(RFPROC|RFMEM|RFNOWAIT, stk, mp, mp->g0, runtime·mstart) < 0) - runtime·throw("newosproc: rfork failed"); -} - -uintptr -runtime·semacreate(void) -{ - return 1; -} - -int32 -runtime·semasleep(int64 ns) -{ - int32 ret; - int32 ms; - - if(ns >= 0) { - if(ns/1000000 > 0x7fffffffll) - ms = 0x7fffffff; - else - ms = ns/1000000; - ret = runtime·plan9_tsemacquire(&m->waitsemacount, ms); - if(ret == 1) - return 0; // success - return -1; // timeout or interrupted - } - - while(runtime·plan9_semacquire(&m->waitsemacount, 1) < 0) { - /* interrupted; try again (c.f. lock_sema.c) */ - } - return 0; // success -} - -void -runtime·semawakeup(M *mp) -{ - runtime·plan9_semrelease(&mp->waitsemacount, 1); -} - -void -os·sigpipe(void) -{ - runtime·throw("too many writes on closed pipe"); -} - -void -runtime·sigpanic(void) -{ - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring(m->notesig); - - if(g->sig == 1 || g->sig == 2) - runtime·throw("fault"); -} - -int32 -runtime·read(int32 fd, void *buf, int32 nbytes) -{ - return runtime·pread(fd, buf, nbytes, -1LL); -} - -int32 -runtime·write(int32 fd, void *buf, int32 nbytes) -{ - return runtime·pwrite(fd, buf, nbytes, -1LL); -} - -uintptr -runtime·memlimit(void) -{ - return 0; -} - -void -runtime·setprof(bool on) -{ - USED(on); -} - -static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n"; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag 7 -void -runtime·badcallback(void) -{ - runtime·pwrite(2, badcallback, sizeof badcallback - 1, -1LL); -} - -static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n"; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag 7 -void -runtime·badsignal(void) -{ - runtime·pwrite(2, badsignal, sizeof badsignal - 1, -1LL); - runtime·exits(badsignal); -} diff --git a/src/pkg/runtime/thread_windows.c b/src/pkg/runtime/thread_windows.c deleted file mode 100644 index c80a38a374..0000000000 --- a/src/pkg/runtime/thread_windows.c +++ /dev/null @@ -1,457 +0,0 @@ -// 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 "type.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" - -#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll" -#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll" -#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll" -#pragma dynimport runtime·CreateWaitableTimer CreateWaitableTimerA "kernel32.dll" -#pragma dynimport runtime·CryptAcquireContextW CryptAcquireContextW "advapi32.dll" -#pragma dynimport runtime·CryptGenRandom CryptGenRandom "advapi32.dll" -#pragma dynimport runtime·CryptReleaseContext CryptReleaseContext "advapi32.dll" -#pragma dynimport runtime·DuplicateHandle DuplicateHandle "kernel32.dll" -#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll" -#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll" -#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll" -#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll" -#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll" -#pragma dynimport runtime·GetSystemInfo GetSystemInfo "kernel32.dll" -#pragma dynimport runtime·GetSystemTimeAsFileTime GetSystemTimeAsFileTime "kernel32.dll" -#pragma dynimport runtime·GetThreadContext GetThreadContext "kernel32.dll" -#pragma dynimport runtime·LoadLibrary LoadLibraryW "kernel32.dll" -#pragma dynimport runtime·ResumeThread ResumeThread "kernel32.dll" -#pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll" -#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll" -#pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll" -#pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll" -#pragma dynimport runtime·Sleep Sleep "kernel32.dll" -#pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll" -#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll" -#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll" -#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll" -#pragma dynimport runtime·NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll" - -extern void *runtime·NtWaitForSingleObject; - -extern void *runtime·CloseHandle; -extern void *runtime·CreateEvent; -extern void *runtime·CreateThread; -extern void *runtime·CreateWaitableTimer; -extern void *runtime·CryptAcquireContextW; -extern void *runtime·CryptGenRandom; -extern void *runtime·CryptReleaseContext; -extern void *runtime·DuplicateHandle; -extern void *runtime·ExitProcess; -extern void *runtime·FreeEnvironmentStringsW; -extern void *runtime·GetEnvironmentStringsW; -extern void *runtime·GetProcAddress; -extern void *runtime·GetStdHandle; -extern void *runtime·GetSystemInfo; -extern void *runtime·GetSystemTimeAsFileTime; -extern void *runtime·GetThreadContext; -extern void *runtime·LoadLibrary; -extern void *runtime·ResumeThread; -extern void *runtime·SetConsoleCtrlHandler; -extern void *runtime·SetEvent; -extern void *runtime·SetThreadPriority; -extern void *runtime·SetWaitableTimer; -extern void *runtime·Sleep; -extern void *runtime·SuspendThread; -extern void *runtime·timeBeginPeriod; -extern void *runtime·WaitForSingleObject; -extern void *runtime·WriteFile; - -static int32 -getproccount(void) -{ - SystemInfo info; - - runtime·stdcall(runtime·GetSystemInfo, 1, &info); - return info.dwNumberOfProcessors; -} - -void -runtime·osinit(void) -{ - // -1 = current process, -2 = current thread - runtime·stdcall(runtime·DuplicateHandle, 7, - (uintptr)-1, (uintptr)-2, (uintptr)-1, &m->thread, - (uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS); - runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1); - runtime·stdcall(runtime·timeBeginPeriod, 1, (uintptr)1); - runtime·ncpu = getproccount(); -} - -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - uintptr handle; - *rnd = nil; - *rnd_len = 0; - if(runtime·stdcall(runtime·CryptAcquireContextW, 5, &handle, nil, nil, - (uintptr)1 /* PROV_RSA_FULL */, - (uintptr)0xf0000000U /* CRYPT_VERIFYCONTEXT */) != 0) { - static byte random_data[HashRandomBytes]; - if(runtime·stdcall(runtime·CryptGenRandom, 3, handle, (uintptr)HashRandomBytes, random_data)) { - *rnd = random_data; - *rnd_len = HashRandomBytes; - } - runtime·stdcall(runtime·CryptReleaseContext, 2, handle, (uintptr)0); - } -} - -void -runtime·goenvs(void) -{ - extern Slice syscall·envs; - - uint16 *env; - String *s; - int32 i, n; - uint16 *p; - - env = runtime·stdcall(runtime·GetEnvironmentStringsW, 0); - - n = 0; - for(p=env; *p; n++) - p += runtime·findnullw(p)+1; - - s = runtime·malloc(n*sizeof s[0]); - - p = env; - for(i=0; i 0x7fffffffLL) - ms = 0x7fffffff; - else { - ms = ns/1000000; - if(ms == 0) - ms = 1; - } - if(runtime·stdcall(runtime·WaitForSingleObject, 2, m->waitsema, ms) != 0) - return -1; // timeout - return 0; -} - -void -runtime·semawakeup(M *mp) -{ - runtime·stdcall(runtime·SetEvent, 1, mp->waitsema); -} - -uintptr -runtime·semacreate(void) -{ - return (uintptr)runtime·stdcall(runtime·CreateEvent, 4, (uintptr)0, (uintptr)0, (uintptr)0, (uintptr)0); -} - -#define STACK_SIZE_PARAM_IS_A_RESERVATION ((uintptr)0x00010000) - -void -runtime·newosproc(M *mp, void *stk) -{ - void *thandle; - - USED(stk); - - thandle = runtime·stdcall(runtime·CreateThread, 6, - nil, (uintptr)0x20000, runtime·tstart_stdcall, mp, - STACK_SIZE_PARAM_IS_A_RESERVATION, nil); - if(thandle == nil) { - runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror()); - runtime·throw("runtime.newosproc"); - } - runtime·atomicstorep(&mp->thread, thandle); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - USED(mp); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - runtime·install_exception_handler(); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ - runtime·remove_exception_handler(); -} - -int64 -runtime·nanotime(void) -{ - int64 filetime; - - runtime·stdcall(runtime·GetSystemTimeAsFileTime, 1, &filetime); - - // Filetime is 100s of nanoseconds since January 1, 1601. - // Convert to nanoseconds since January 1, 1970. - return (filetime - 116444736000000000LL) * 100LL; -} - -void -time·now(int64 sec, int32 usec) -{ - int64 ns; - - ns = runtime·nanotime(); - sec = ns / 1000000000LL; - usec = ns - sec * 1000000000LL; - FLUSH(&sec); - FLUSH(&usec); -} - -// Calling stdcall on os stack. -#pragma textflag 7 -void * -runtime·stdcall(void *fn, int32 count, ...) -{ - WinCall c; - - c.fn = fn; - c.n = count; - c.args = (uintptr*)&count + 1; - runtime·asmcgocall(runtime·asmstdcall, &c); - return (void*)c.r1; -} - -uint32 -runtime·issigpanic(uint32 code) -{ - switch(code) { - case EXCEPTION_ACCESS_VIOLATION: - case EXCEPTION_INT_DIVIDE_BY_ZERO: - case EXCEPTION_INT_OVERFLOW: - case EXCEPTION_FLT_DENORMAL_OPERAND: - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - case EXCEPTION_FLT_INEXACT_RESULT: - case EXCEPTION_FLT_OVERFLOW: - case EXCEPTION_FLT_UNDERFLOW: - return 1; - } - return 0; -} - -void -runtime·sigpanic(void) -{ - switch(g->sig) { - case EXCEPTION_ACCESS_VIOLATION: - if(g->sigcode1 < 0x1000) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); - } - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case EXCEPTION_INT_DIVIDE_BY_ZERO: - runtime·panicstring("integer divide by zero"); - case EXCEPTION_INT_OVERFLOW: - runtime·panicstring("integer overflow"); - case EXCEPTION_FLT_DENORMAL_OPERAND: - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - case EXCEPTION_FLT_INEXACT_RESULT: - case EXCEPTION_FLT_OVERFLOW: - case EXCEPTION_FLT_UNDERFLOW: - runtime·panicstring("floating point error"); - } - runtime·throw("fault"); -} - -extern void *runtime·sigtramp; - -void -runtime·initsig(void) -{ - // following line keeps sigtramp alive at link stage - // if there's a better way please write it here - void *p = runtime·sigtramp; - USED(p); -} - -uint32 -runtime·ctrlhandler1(uint32 type) -{ - int32 s; - - switch(type) { - case CTRL_C_EVENT: - case CTRL_BREAK_EVENT: - s = SIGINT; - break; - default: - return 0; - } - - if(runtime·sigsend(s)) - return 1; - runtime·exit(2); // SIGINT, SIGTERM, etc - return 0; -} - -extern void runtime·dosigprof(Context *r, G *gp); -extern void runtime·profileloop(void); -static void *profiletimer; - -static void -profilem(M *mp) -{ - extern M runtime·m0; - extern uint32 runtime·tls0[]; - byte rbuf[sizeof(Context)+15]; - Context *r; - void *tls; - G *gp; - - tls = mp->tls; - if(mp == &runtime·m0) - tls = runtime·tls0; - gp = *(G**)tls; - - if(gp != nil && gp != mp->g0 && gp->status != Gsyscall) { - // align Context to 16 bytes - r = (Context*)((uintptr)(&rbuf[15]) & ~15); - r->ContextFlags = CONTEXT_CONTROL; - runtime·stdcall(runtime·GetThreadContext, 2, mp->thread, r); - runtime·dosigprof(r, gp); - } -} - -void -runtime·profileloop1(void) -{ - M *mp, *allm; - void *thread; - - runtime·stdcall(runtime·SetThreadPriority, 2, - (uintptr)-2, (uintptr)THREAD_PRIORITY_HIGHEST); - - for(;;) { - runtime·stdcall(runtime·WaitForSingleObject, 2, profiletimer, (uintptr)-1); - allm = runtime·atomicloadp(&runtime·allm); - for(mp = allm; mp != nil; mp = mp->alllink) { - thread = runtime·atomicloadp(&mp->thread); - if(thread == nil) - continue; - runtime·stdcall(runtime·SuspendThread, 1, thread); - if(mp->profilehz != 0) - profilem(mp); - runtime·stdcall(runtime·ResumeThread, 1, thread); - } - } -} - -void -runtime·resetcpuprofiler(int32 hz) -{ - static Lock lock; - void *timer, *thread; - int32 ms; - int64 due; - - runtime·lock(&lock); - if(profiletimer == nil) { - timer = runtime·stdcall(runtime·CreateWaitableTimer, 3, nil, nil, nil); - runtime·atomicstorep(&profiletimer, timer); - thread = runtime·stdcall(runtime·CreateThread, 6, - nil, nil, runtime·profileloop, nil, nil, nil); - runtime·stdcall(runtime·CloseHandle, 1, thread); - } - runtime·unlock(&lock); - - ms = 0; - due = 1LL<<63; - if(hz > 0) { - ms = 1000 / hz; - if(ms == 0) - ms = 1; - due = ms * -10000; - } - runtime·stdcall(runtime·SetWaitableTimer, 6, - profiletimer, &due, (uintptr)ms, nil, nil, nil); - runtime·atomicstore((uint32*)&m->profilehz, hz); -} - -void -os·sigpipe(void) -{ - runtime·throw("too many writes on closed pipe"); -} - -uintptr -runtime·memlimit(void) -{ - return 0; -} - -void -runtime·setprof(bool on) -{ - USED(on); -} - -int8 runtime·badcallbackmsg[] = "runtime: cgo callback on thread not created by Go.\n"; -int32 runtime·badcallbacklen = sizeof runtime·badcallbackmsg - 1; - -int8 runtime·badsignalmsg[] = "runtime: signal received on thread not created by Go.\n"; -int32 runtime·badsignallen = sizeof runtime·badsignalmsg - 1; -- cgit v1.3-5-g9baa