// license that can be found in the LICENSE file.
/*
- Package runtime contains operations that interact with Go's runtime system,
- such as functions to control goroutines. It also includes the low-level type information
- used by the reflect package; see reflect's documentation for the programmable
- interface to the run-time type system.
+Package runtime contains operations that interact with Go's runtime system,
+such as functions to control goroutines. It also includes the low-level type information
+used by the reflect package; see reflect's documentation for the programmable
+interface to the run-time type system.
+
+Environment Variables
+
+The following environment variables ($name or %name%, depending on the host
+operating system) control the run-time behavior of Go programs. The meanings
+and use may change from release to release.
+
+The GOGC variable sets the initial garbage collection target percentage.
+A collection is triggered when the ratio of freshly allocated data to live data
+remaining after the previous collection reaches this percentage. The default
+is GOGC=100. Setting GOGC=off disables the garbage collector entirely.
+The runtime/debug package's SetGCPercent function allows changing this
+percentage at run time. See http://golang.org/pkg/runtime/debug/#SetGCPercent.
+
+The GOGCTRACE variable controls debug output from the garbage collector.
+Setting GOGCTRACE=1 causes the garbage collector to emit a single line to standard
+error at each collection, summarizing the amount of memory collected and the
+length of the pause. Setting GOGCTRACE=2 emits the same summary but also
+repeats each collection.
+
+The GOMAXPROCS variable limits the number of operating system threads that
+can execute user-level Go code simultaneously. There is no limit to the number of threads
+that can be blocked in system calls on behalf of Go code; those do not count against
+the GOMAXPROCS limit. This package's GOMAXPROCS function queries and changes
+the limit.
+
+The GOTRACEBACK variable controls the amount of output generated when a Go
+program fails due to an unrecovered panic or an unexpected runtime condition.
+By default, a failure prints a stack trace for every extant goroutine, eliding functions
+internal to the run-time system, and then exits with exit code 2.
+If GOTRACEBACK=0, the per-goroutine stack traces are omitted entirely.
+If GOTRACEBACK=1, the default behavior is used.
+If GOTRACEBACK=2, the per-goroutine stack traces include run-time functions.
+If GOTRACEBACK=crash, the per-goroutine stack traces include run-time functions,
+and if possible the program crashes in an operating-specific manner instead of
+exiting. For example, on Unix systems, the program raises SIGABRT to trigger a
+core dump.
+
+The GOARCH, GOOS, GOPATH, and GOROOT environment variables complete
+the set of Go environment variables. They influence the building of Go programs
+(see http://golang.org/cmd/go and http://golang.org/pkg/go/build).
+GOARCH, GOOS, and GOROOT are recorded at compile time and made available by
+constants or functions in this package, but they do not influence the execution
+of the run-time system.
*/
package runtime
runtime·notify(runtime·sigtramp);
}
+void
+runtime·crash(void)
+{
+ runtime·notify(nil);
+ *(int32*)0 = 0;
+}
+
void
runtime·get_random_data(byte **rnd, int32 *rnd_len)
{
int32
runtime·sighandler(void *v, int8 *s, G *gp)
{
+ bool crash;
Ureg *ureg;
uintptr *sp;
SigTab *sig, *nsig;
runtime·printf("PC=%X\n", ureg->pc);
runtime·printf("\n");
- if(runtime·gotraceback()) {
+ if(runtime·gotraceback(&crash)) {
runtime·traceback((void*)ureg->pc, (void*)ureg->sp, 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(ureg);
}
+
+ if(crash)
+ runtime·crash();
+
runtime·goexitsall("");
runtime·exits(s);
int32
runtime·sighandler(void *v, int8 *s, G *gp)
{
+ bool crash;
Ureg *ureg;
uintptr *sp;
SigTab *sig, *nsig;
runtime·printf("PC=%X\n", ureg->ip);
runtime·printf("\n");
- if(runtime·gotraceback()) {
+ if(runtime·gotraceback(&crash)) {
runtime·traceback((void*)ureg->ip, (void*)ureg->sp, 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(ureg);
}
+
+ if(crash)
+ runtime·crash();
+
runtime·goexitsall("");
runtime·exits(s);
int8 runtime·badsignalmsg[] = "runtime: signal received on thread not created by Go.\n";
int32 runtime·badsignallen = sizeof runtime·badsignalmsg - 1;
+
+void
+runtime·crash(void)
+{
+ // TODO: This routine should do whatever is needed
+ // to make the Windows program abort/crash as it
+ // would if Go was not intercepting signals.
+ // On Unix the routine would remove the custom signal
+ // handler and then raise a signal (like SIGABRT).
+ // Something like that should happen here.
+ // It's okay to leave this empty for now: if crash returns
+ // the ordinary exit-after-panic happens.
+}
uint32
runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
{
+ bool crash;
uintptr *sp;
switch(info->ExceptionCode) {
}
runtime·printf("\n");
- if(runtime·gotraceback()){
+ if(runtime·gotraceback(&crash)){
runtime·traceback((void*)r->Eip, (void*)r->Esp, 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(r);
}
+
+ if(crash)
+ runtime·crash();
+
runtime·exit(2);
return 0;
uint32
runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
{
+ bool crash;
uintptr *sp;
switch(info->ExceptionCode) {
}
runtime·printf("\n");
- if(runtime·gotraceback()){
+ if(runtime·gotraceback(&crash)){
runtime·traceback((void*)r->Rip, (void*)r->Rsp, 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(r);
}
+
+ if(crash)
+ runtime·crash();
runtime·exit(2);
return 0;
runtime·dopanic(int32 unused)
{
static bool didothers;
+ bool crash;
if(g->sig != 0)
runtime·printf("[signal %x code=%p addr=%p pc=%p]\n",
g->sig, g->sigcode0, g->sigcode1, g->sigpc);
- if(runtime·gotraceback()){
+ if(runtime·gotraceback(&crash)){
if(g != m->g0) {
runtime·printf("\n");
runtime·goroutineheader(g);
runtime·lock(&deadlock);
runtime·lock(&deadlock);
}
+
+ if(crash)
+ runtime·crash();
runtime·exit(2);
}
G *gp;
int32 traceback;
- traceback = runtime·gotraceback();
+ traceback = runtime·gotraceback(nil);
for(gp = runtime·allg; gp != nil; gp = gp->alllink) {
if(gp == me || gp->status == Gdead)
continue;
*/
void runtime·sigpanic(void);
+// The GOTRACEBACK environment variable controls the
+// behavior of a Go program that is crashing and exiting.
+// GOTRACEBACK=0 suppress all tracebacks
+// GOTRACEBACK=1 default behavior - show tracebacks but exclude runtime frames
+// GOTRACEBACK=2 show tracebacks including runtime frames
+// GOTRACEBACK=crash show tracebacks including runtime frames, then crash (core dump etc)
int32
-runtime·gotraceback(void)
+runtime·gotraceback(bool *crash)
{
byte *p;
+ if(crash != nil)
+ *crash = false;
p = runtime·getenv("GOTRACEBACK");
if(p == nil || p[0] == '\0')
return 1; // default is on
+ if(runtime·strcmp(p, (byte*)"crash") == 0) {
+ if(crash != nil)
+ *crash = true;
+ return 2; // extra information
+ }
return runtime·atoi(p);
}
void runtime·initsig(void);
void runtime·sigenable(uint32 sig);
void runtime·sigdisable(uint32 sig);
-int32 runtime·gotraceback(void);
+int32 runtime·gotraceback(bool *crash);
void runtime·goroutineheader(G*);
void runtime·traceback(uint8 *pc, uint8 *sp, uint8 *lr, G* gp);
void runtime·tracebackothers(G*);
void runtime·netpollinit(void);
int32 runtime·netpollopen(int32, PollDesc*);
void runtime·netpollready(G**, PollDesc*, int32);
+void runtime·crash(void);
#pragma varargck argpos runtime·printf 1
#pragma varargck type "d" int32
{
uintptr *sp;
SigTab *t;
+ bool crash;
if(sig == SIGPROF) {
if(gp != m->g0 && gp != m->gsignal)
}
runtime·printf("\n");
- if(runtime·gotraceback()){
+ if(runtime·gotraceback(&crash)){
runtime·traceback((void*)SIG_EIP(info, ctxt), (void*)SIG_ESP(info, ctxt), 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(info, ctxt);
}
+
+ if(crash)
+ runtime·crash();
runtime·exit(2);
}
{
uintptr *sp;
SigTab *t;
+ bool crash;
if(sig == SIGPROF) {
if(gp != m->g0 && gp != m->gsignal)
}
runtime·printf("\n");
- if(runtime·gotraceback()){
+ if(runtime·gotraceback(&crash)){
runtime·traceback((void*)SIG_RIP(info, ctxt), (void*)SIG_RSP(info, ctxt), 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(info, ctxt);
}
+
+ if(crash)
+ runtime·crash();
runtime·exit(2);
}
runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
{
SigTab *t;
+ bool crash;
if(sig == SIGPROF) {
if(gp != m->g0 && gp != m->gsignal)
}
runtime·printf("\n");
- if(runtime·gotraceback()){
+ if(runtime·gotraceback(&crash)){
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(info, ctxt);
}
+
+ if(crash)
+ runtime·crash();
runtime·exit(2);
}
os·sigpipe(void)
{
runtime·setsig(SIGPIPE, SIG_DFL, false);
- runtime·raisesigpipe();
+ runtime·raise(SIGPIPE);
+}
+
+void
+runtime·crash(void)
+{
+#ifdef GOOS_darwin
+ // OS X core dumps are linear dumps of the mapped memory,
+ // from the first virtual byte to the last, with zeros in the gaps.
+ // Because of the way we arrange the address space on 64-bit systems,
+ // this means the OS X core file will be >128 GB and even on a zippy
+ // workstation can take OS X well over an hour to write (uninterruptible).
+ // Save users from making that mistake.
+ if(sizeof(void*) == 8)
+ return;
+#endif
+
+ runtime·setsig(SIGABRT, SIG_DFL, false);
+ runtime·raise(SIGABRT);
}
GoSighandler* runtime·getsig(int32);
void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
-void runtime·raisesigpipe(void);
+void runtime·raise(int32);
+
if(current && m->throwing > 0)
return 1;
if(traceback < 0)
- traceback = runtime·gotraceback();
+ traceback = runtime·gotraceback(nil);
return traceback > 1 || f != nil && contains(f->name, ".") && !hasprefix(f->name, "runtime.");
}
INT $0x80
RET
-TEXT runtime·raisesigpipe(SB),7,$8
- get_tls(CX)
- MOVL m(CX), DX
- MOVL m_procid(DX), DX
- MOVL DX, 0(SP) // thread_port
- MOVL $13, 4(SP) // signal: SIGPIPE
- MOVL $328, AX // __pthread_kill
+TEXT runtime·raise(SB),7,$16
+ MOVL $20, AX // getpid
+ INT $0x80
+ MOVL AX, 4(SP) // pid
+ MOVL sig+0(FP), AX
+ MOVL AX, 8(SP) // signal
+ MOVL $1, 12(SP) // posix
+ MOVL $37, AX // kill
INT $0x80
RET
SYSCALL
RET
-TEXT runtime·raisesigpipe(SB),7,$24
- get_tls(CX)
- MOVQ m(CX), DX
- MOVL $13, DI // arg 1 SIGPIPE
- MOVQ m_procid(DX), SI // arg 2 thread_port
- MOVL $(0x2000000+328), AX // syscall entry __pthread_kill
+TEXT runtime·raise(SB),7,$24
+ MOVL $(0x2000000+20), AX // getpid
+ SYSCALL
+ MOVQ AX, DI // arg 1 - pid
+ MOVL sig+0(FP), SI // arg 2 - signal
+ MOVL $1, DX // arg 3 - posix
+ MOVL $(0x2000000+37), AX // kill
SYSCALL
RET
INT $0x80
RET
-TEXT runtime·raisesigpipe(SB),7,$12
+TEXT runtime·raise(SB),7,$16
// thr_self(&8(SP))
LEAL 8(SP), AX
- MOVL AX, 0(SP)
+ MOVL AX, 4(SP)
MOVL $432, AX
INT $0x80
// thr_kill(self, SIGPIPE)
MOVL 8(SP), AX
- MOVL AX, 0(SP)
- MOVL $13, 4(SP)
+ MOVL AX, 4(SP)
+ MOVL sig+0(FP), AX
+ MOVL AX, 8(SP)
MOVL $433, AX
INT $0x80
RET
SYSCALL
RET
-TEXT runtime·raisesigpipe(SB),7,$16
+TEXT runtime·raise(SB),7,$16
// thr_self(&8(SP))
LEAQ 8(SP), DI // arg 1 &8(SP)
MOVL $432, AX
SYSCALL
// thr_kill(self, SIGPIPE)
MOVQ 8(SP), DI // arg 1 id
- MOVQ $13, SI // arg 2 SIGPIPE
+ MOVL sig+0(FP), SI // arg 2
MOVL $433, AX
SYSCALL
RET
SWI $194
RET
-TEXT runtime·raisesigpipe(SB),7,$8
+TEXT runtime·raise(SB),7,$8
// thr_self(&4(R13))
MOVW $4(R13), R0 // arg 1 &4(R13)
SWI $432
// thr_kill(self, SIGPIPE)
MOVW 4(R13), R0 // arg 1 id
- MOVW $13, R1 // arg 2 SIGPIPE
+ MOVW sig+0(FP), R1 // arg 2 - signal
SWI $433
RET
CALL *runtime·_vdso(SB)
RET
-TEXT runtime·raisesigpipe(SB),7,$12
+TEXT runtime·raise(SB),7,$12
MOVL $224, AX // syscall - gettid
CALL *runtime·_vdso(SB)
- MOVL AX, 0(SP) // arg 1 tid
- MOVL $13, 4(SP) // arg 2 SIGPIPE
+ MOVL AX, BX // arg 1 tid
+ MOVL sig+0(FP), CX // arg 2 signal
MOVL $238, AX // syscall - tkill
CALL *runtime·_vdso(SB)
RET
SYSCALL
RET
-TEXT runtime·raisesigpipe(SB),7,$12
+TEXT runtime·raise(SB),7,$12
MOVL $186, AX // syscall - gettid
SYSCALL
MOVL AX, DI // arg 1 tid
- MOVL $13, SI // arg 2 SIGPIPE
+ MOVL sig+0(FP), SI // arg 2
MOVL $200, AX // syscall - tkill
SYSCALL
RET
MOVW $1003, R1
MOVW R0, (R1) // fail hard
-TEXT runtime·raisesigpipe(SB),7,$-4
+TEXT runtime·raise(SB),7,$-4
MOVW $SYS_gettid, R7
SWI $0
// arg 1 tid already in R0 from gettid
- MOVW $13, R1 // arg 2 SIGPIPE
+ MOVW sig+0(FP), R1 // arg 2 - signal
MOVW $SYS_tkill, R7
SWI $0
RET
INT $0x80
RET
-TEXT runtime·raisesigpipe(SB),7,$12
+TEXT runtime·raise(SB),7,$12
MOVL $311, AX // sys__lwp_self
INT $0x80
MOVL $0, 0(SP)
MOVL AX, 4(SP) // arg 1 - target
- MOVL $13, 8(SP) // arg 2 - signo == SIGPIPE
+ MOVL sig+0(FP), AX
+ MOVL AX, 8(SP) // arg 2 - signo
MOVL $318, AX // sys__lwp_kill
INT $0x80
RET
SYSCALL
RET
-TEXT runtime·raisesigpipe(SB),7,$16
+TEXT runtime·raise(SB),7,$16
MOVL $311, AX // sys__lwp_self
SYSCALL
MOVQ AX, DI // arg 1 - target
- MOVQ $13, SI // arg 2 - signo == SIGPIPE
+ MOVL sig+0(FP), SI // arg 2 - signo
MOVL $318, AX // sys__lwp_kill
SYSCALL
RET
SWI $0xa001ae // sys_nanosleep
RET
-TEXT runtime·raisesigpipe(SB),7,$16
+TEXT runtime·raise(SB),7,$16
SWI $0xa00137 // sys__lwp_self, the returned R0 is arg 1
- MOVW $13, R1 // arg 2 - signo == SIGPIPE
+ MOVW sig+0(FP), R1 // arg 2 - signal
SWI $0xa0013e // sys__lwp_kill
RET
INT $0x80
RET
-TEXT runtime·raisesigpipe(SB),7,$12
+TEXT runtime·raise(SB),7,$12
MOVL $299, AX // sys_getthrid
INT $0x80
MOVL $0, 0(SP)
MOVL AX, 4(SP) // arg 1 - pid
- MOVL $13, 8(SP) // arg 2 - signum == SIGPIPE
+ MOVL sig+0(FP), AX
+ MOVL AX, 8(SP) // arg 2 - signum
MOVL $37, AX // sys_kill
INT $0x80
RET
SYSCALL
RET
-TEXT runtime·raisesigpipe(SB),7,$16
+TEXT runtime·raise(SB),7,$16
MOVL $299, AX // sys_getthrid
SYSCALL
MOVQ AX, DI // arg 1 - pid
- MOVQ $13, SI // arg 2 - signum == SIGPIPE
+ MOVL sig+0(FP), SI // arg 2 - signum
MOVL $37, AX // sys_kill
SYSCALL
RET