diff options
Diffstat (limited to 'src/pkg/runtime')
41 files changed, 668 insertions, 365 deletions
diff --git a/src/pkg/runtime/Makefile b/src/pkg/runtime/Makefile index 521c095b9..e4cc08175 100644 --- a/src/pkg/runtime/Makefile +++ b/src/pkg/runtime/Makefile @@ -40,11 +40,8 @@ OFILES_386=\ vlop.$O\ vlrt.$O\ -GOARM?=6 - # arm-specific object files OFILES_arm=\ - cas$(GOARM).$O\ memset.$O\ softfloat.$O\ vlop.$O\ @@ -94,6 +91,7 @@ HFILES=\ runtime.h\ hashmap.h\ malloc.h\ + stack.h\ $(GOARCH)/asm.h\ $(GOOS)/os.h\ $(GOOS)/signals.h\ @@ -129,7 +127,7 @@ mkversion: mkversion.c quietgcc -o $@ -I "$(GOROOT)/include" $< "$(GOROOT)/lib/lib9.a" version.go: mkversion - ./mkversion >version.go + GOROOT="$(GOROOT_FINAL)" ./mkversion >version.go version_$(GOARCH).go: (echo 'package runtime'; echo 'const theGoarch = "$(GOARCH)"') >$@ @@ -141,13 +139,13 @@ version_$(GOOS).go: ./goc2c "`pwd`/$<" > $@.tmp mv -f $@.tmp $@ -%.$O: $(GOARCH)/%.c +%.$O: $(GOARCH)/%.c $(HFILES) $(CC) $(CFLAGS) $< -%.$O: $(GOOS)/%.c +%.$O: $(GOOS)/%.c $(HFILES) $(CC) $(CFLAGS) $< -%.$O: $(GOOS)/$(GOARCH)/%.c +%.$O: $(GOOS)/$(GOARCH)/%.c $(HFILES) $(CC) $(CFLAGS) $< %.$O: $(GOARCH)/%.s $(GOARCH)/asm.h diff --git a/src/pkg/runtime/amd64/asm.s b/src/pkg/runtime/amd64/asm.s index b6642c13c..cc05435f7 100644 --- a/src/pkg/runtime/amd64/asm.s +++ b/src/pkg/runtime/amd64/asm.s @@ -317,6 +317,26 @@ TEXT runtime·cas(SB), 7, $0 MOVL $1, AX RET +// bool casp(void **val, void *old, void *new) +// Atomically: +// if(*val == old){ +// *val = new; +// return 1; +// } else +// return 0; +TEXT runtime·casp(SB), 7, $0 + MOVQ 8(SP), BX + MOVQ 16(SP), AX + MOVQ 24(SP), CX + LOCK + CMPXCHGQ CX, 0(BX) + JZ 3(PC) + MOVL $0, AX + RET + MOVL $1, AX + RET + + // void jmpdefer(fn, sp); // called from deferreturn. // 1. pop the caller diff --git a/src/pkg/runtime/amd64/traceback.c b/src/pkg/runtime/amd64/traceback.c index d3aae0db9..0f6733c36 100644 --- a/src/pkg/runtime/amd64/traceback.c +++ b/src/pkg/runtime/amd64/traceback.c @@ -164,12 +164,35 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 max) continue; } + if(pcbuf == nil && f->entry == (uintptr)runtime·lessstack && g == m->g0) { + // Lessstack is running on scheduler stack. Switch to original goroutine. + runtime·printf("----- lessstack called from goroutine %d -----\n", m->curg->goid); + g = m->curg; + stk = (Stktop*)g->stackbase; + sp = stk->gobuf.sp; + pc = (uintptr)stk->gobuf.pc; + fp = nil; + lr = 0; + continue; + } + // Unwind to next frame. pc = lr; lr = 0; sp = fp; fp = nil; } + + if(pcbuf == nil && (pc = g->gopc) != 0 && (f = runtime·findfunc(pc)) != nil) { + runtime·printf("----- goroutine created by -----\n%S", f->name); + if(pc > f->entry) + runtime·printf("+%p", (uintptr)(pc - f->entry)); + tracepc = pc; // back up to CALL instruction for funcline. + if(n > 0 && pc > f->entry) + tracepc--; + runtime·printf(" %S:%d\n", f->src, runtime·funcline(f, tracepc)); + } + return n; } diff --git a/src/pkg/runtime/arm/asm.s b/src/pkg/runtime/arm/asm.s index a4e4b3283..f9fe7e628 100644 --- a/src/pkg/runtime/arm/asm.s +++ b/src/pkg/runtime/arm/asm.s @@ -12,10 +12,10 @@ TEXT _rt0_arm(SB),7,$-4 // use R13 instead of SP to avoid linker rewriting the offsets MOVW 0(R13), R0 // argc MOVW $4(R13), R1 // argv - SUB $128, R13 // plenty of scratch + SUB $64, R13 // plenty of scratch AND $~7, R13 - MOVW R0, 120(R13) // save argc, argv away - MOVW R1, 124(R13) + MOVW R0, 60(R13) // save argc, argv away + MOVW R1, 64(R13) // set up m and g registers // g is R10, m is R9 @@ -34,9 +34,9 @@ TEXT _rt0_arm(SB),7,$-4 BL runtime·check(SB) // saved argc, argv - MOVW 120(R13), R0 + MOVW 60(R13), R0 MOVW R0, 4(R13) - MOVW 124(R13), R1 + MOVW 64(R13), R1 MOVW R1, 8(R13) BL runtime·args(SB) BL runtime·osinit(SB) @@ -274,3 +274,34 @@ TEXT runtime·abort(SB),7,$-4 TEXT runtime·runcgocallback(SB),7,$0 MOVW $0, R0 MOVW (R0), R1 + +// bool armcas(int32 *val, int32 old, int32 new) +// Atomically: +// if(*val == old){ +// *val = new; +// return 1; +// }else +// return 0; +// +// To implement runtime·cas in ../$GOOS/arm/sys.s +// using the native instructions, use: +// +// TEXT runtime·cas(SB),7,$0 +// B runtime·armcas(SB) +// +TEXT runtime·armcas(SB),7,$0 + MOVW valptr+0(FP), R1 + MOVW old+4(FP), R2 + MOVW new+8(FP), R3 +casl: + LDREX (R1), R0 + CMP R0, R2 + BNE casfail + STREX R3, (R1), R0 + CMP $0, R0 + BNE casl + MOVW $1, R0 + RET +casfail: + MOVW $0, R0 + RET diff --git a/src/pkg/runtime/arm/cas5.s b/src/pkg/runtime/arm/cas5.s deleted file mode 100644 index 20bd3c3e2..000000000 --- a/src/pkg/runtime/arm/cas5.s +++ /dev/null @@ -1,43 +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 "arm/asm.h" - -// This version works on pre v6 architectures - -// bool cas(int32 *val, int32 old, int32 new) -// Atomically: -// if(*val == old){ -// *val = new; -// return 1; -// }else -// return 0; - -TEXT runtime·cas(SB),7,$0 - MOVW 0(FP), R0 // *val - MOVW 4(FP), R1 // old - MOVW 8(FP), R2 // new - MOVW $1, R3 - MOVW $runtime·cas_mutex(SB), R4 -l: - SWPW (R4), R3 // acquire mutex - CMP $0, R3 - BNE fail0 - - MOVW (R0), R5 - CMP R1, R5 - BNE fail1 - - MOVW R2, (R0) - MOVW R3, (R4) // release mutex - MOVW $1, R0 - RET -fail1: - MOVW R3, (R4) // release mutex -fail0: - MOVW $0, R0 - RET - -DATA runtime·cas_mutex(SB)/4, $0 -GLOBL runtime·cas_mutex(SB), $4 diff --git a/src/pkg/runtime/arm/cas6.s b/src/pkg/runtime/arm/cas6.s deleted file mode 100644 index 43788b28a..000000000 --- a/src/pkg/runtime/arm/cas6.s +++ /dev/null @@ -1,29 +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. - -// bool cas(int32 *val, int32 old, int32 new) -// Atomically: -// if(*val == old){ -// *val = new; -// return 1; -// }else -// return 0; - -TEXT runtime·cas(SB),7,$0 - MOVW 0(FP), R1 // *val - MOVW 4(FP), R2 // old - MOVW 8(FP), R3 // new -l: - LDREX (R1), R0 - CMP R0, R2 - BNE fail - STREX R3, (R1), R0 - CMP $0, R0 - BNE l - MOVW $1, R0 - RET -fail: - MOVW $0, R0 - RET - diff --git a/src/pkg/runtime/arm/traceback.c b/src/pkg/runtime/arm/traceback.c index 2307e98e8..ad3096823 100644 --- a/src/pkg/runtime/arm/traceback.c +++ b/src/pkg/runtime/arm/traceback.c @@ -9,6 +9,10 @@ void runtime·deferproc(void); void runtime·newproc(void); void runtime·newstack(void); void runtime·morestack(void); +void _div(void); +void _mod(void); +void _divu(void); +void _modu(void); static int32 gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, int32 max) @@ -113,7 +117,7 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i // Print during crash. // main+0xf /home/rsc/go/src/runtime/x.go:23 // main(0x1, 0x2, 0x3) - runtime·printf("%S", f->name); + runtime·printf("[%p] %S", fp, f->name); if(pc > f->entry) runtime·printf("+%p", (uintptr)(pc - f->entry)); tracepc = pc; // back up to CALL instruction for funcline. @@ -145,12 +149,43 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i continue; } + if(pcbuf == nil && f->entry == (uintptr)runtime·lessstack && g == m->g0) { + runtime·printf("----- lessstack called from goroutine %d -----\n", m->curg->goid); + g = m->curg; + stk = (Stktop*)g->stackbase; + sp = stk->gobuf.sp; + pc = (uintptr)stk->gobuf.pc; + fp = nil; + lr = 0; + continue; + } + // Unwind to next frame. pc = lr; lr = 0; sp = fp; fp = nil; + + // If this was div or divu or mod or modu, the caller had + // an extra 8 bytes on its stack. Adjust sp. + if(f->entry == (uintptr)_div || f->entry == (uintptr)_divu || f->entry == (uintptr)_mod || f->entry == (uintptr)_modu) + sp += 8; + + // If this was deferproc or newproc, the caller had an extra 12. + if(f->entry == (uintptr)runtime·deferproc || f->entry == (uintptr)runtime·newproc) + sp += 12; } + + if(pcbuf == nil && (pc = g->gopc) != 0 && (f = runtime·findfunc(pc)) != nil) { + runtime·printf("----- goroutine created by -----\n%S", f->name); + if(pc > f->entry) + runtime·printf("+%p", (uintptr)(pc - f->entry)); + tracepc = pc; // back up to CALL instruction for funcline. + if(n > 0 && pc > f->entry) + tracepc -= sizeof(uintptr); + runtime·printf(" %S:%d\n", f->src, runtime·funcline(f, tracepc)); + } + return n; } diff --git a/src/pkg/runtime/cgocall.c b/src/pkg/runtime/cgocall.c index 74e5a3085..741e8f0b8 100644 --- a/src/pkg/runtime/cgocall.c +++ b/src/pkg/runtime/cgocall.c @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. #include "runtime.h" +#include "stack.h" #include "cgocall.h" void *initcgo; /* filled in by dynamic linker when Cgo is available */ @@ -70,7 +71,7 @@ runtime·cgocallback(void (*fn)(void), void *arg, int32 argsize) runtime·startcgocallback(g1); sp = g1->sched.sp - argsize; - if(sp < g1->stackguard - StackGuard + 8) // +8 for return address + if(sp < g1->stackguard - StackGuard - StackSystem + 8) // +8 for return address runtime·throw("g stack overflow in cgocallback"); runtime·mcpy(sp, arg, argsize); diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c index 8d3ac2ca4..3177c2295 100644 --- a/src/pkg/runtime/chan.c +++ b/src/pkg/runtime/chan.c @@ -495,17 +495,27 @@ runtime·selectnbrecv(byte *v, Hchan *c, bool ok) runtime·chanrecv(c, v, &ok, nil); } +static void newselect(int32, Select**); + // newselect(size uint32) (sel *byte); #pragma textflag 7 void runtime·newselect(int32 size, ...) { - int32 n, o; + int32 o; Select **selp; - Select *sel; o = runtime·rnd(sizeof(size), Structrnd); selp = (Select**)((byte*)&size + o); + newselect(size, selp); +} + +static void +newselect(int32 size, Select **selp) +{ + int32 n; + Select *sel; + n = 0; if(size > 1) n = size-1; @@ -589,11 +599,19 @@ runtime·selectrecv(Select *sel, Hchan *c, ...) } -// selectdefaul(sel *byte) (selected bool); +static void selectdefault(Select*, void*); + +// selectdefault(sel *byte) (selected bool); #pragma textflag 7 void runtime·selectdefault(Select *sel, ...) { + selectdefault(sel, runtime·getcallerpc(&sel)); +} + +static void +selectdefault(Select *sel, void *callerpc) +{ int32 i; Scase *cas; @@ -603,7 +621,7 @@ runtime·selectdefault(Select *sel, ...) sel->ncase = i+1; cas = runtime·mal(sizeof *cas); sel->scase[i] = cas; - cas->pc = runtime·getcallerpc(&sel); + cas->pc = callerpc; cas->chan = nil; cas->so = runtime·rnd(sizeof(sel), Structrnd); @@ -662,23 +680,32 @@ runtime·block(void) runtime·gosched(); } +static void* selectgo(Select**); + // selectgo(sel *byte); // // overwrites return pc on stack to signal which case of the select // to run, so cannot appear at the top of a split stack. -// frame has 6 pointers and 4 int32 so 64 bytes max. -// that's less than StackGuard-StackSmall, so okay. #pragma textflag 7 void runtime·selectgo(Select *sel) { + runtime·setcallerpc(&sel, selectgo(&sel)); +} + +static void* +selectgo(Select **selp) +{ + Select *sel; uint32 o, i, j; Scase *cas, *dfl; Hchan *c; SudoG *sg; G *gp; byte *as; + void *pc; + sel = *selp; if(runtime·gcwaiting) runtime·gosched(); @@ -889,16 +916,18 @@ retc: selunlock(sel); // return to pc corresponding to chosen case - runtime·setcallerpc(&sel, cas->pc); - as = (byte*)&sel + cas->so; + + pc = cas->pc; + as = (byte*)selp + cas->so; freesel(sel); *as = true; - return; + return pc; sclose: // send on closed channel selunlock(sel); runtime·panicstring("send on closed channel"); + return nil; // not reached } // closechan(sel *byte); diff --git a/src/pkg/runtime/darwin/386/signal.c b/src/pkg/runtime/darwin/386/signal.c index 33f47d44f..aeef5de3f 100644 --- a/src/pkg/runtime/darwin/386/signal.c +++ b/src/pkg/runtime/darwin/386/signal.c @@ -34,20 +34,19 @@ runtime·signame(int32 sig) } void -runtime·sighandler(int32 sig, Siginfo *info, void *context) +runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) { Ucontext *uc; Mcontext *mc; Regs *r; uintptr *sp; - G *gp; byte *pc; uc = context; mc = uc->uc_mcontext; r = &mc->ss; - if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) { + if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) { // Work around Leopard bug that doesn't set FPE_INTDIV. // Look at instruction to see if it is a divide. // Not necessary in Snow Leopard (si_code will be != 0). @@ -103,12 +102,11 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context) runtime·printf("\n"); if(runtime·gotraceback()){ - runtime·traceback((void*)r->eip, (void*)r->esp, 0, m->curg); - runtime·tracebackothers(m->curg); + runtime·traceback((void*)r->eip, (void*)r->esp, 0, gp); + runtime·tracebackothers(gp); runtime·dumpregs(r); } - runtime·breakpoint(); runtime·exit(2); } diff --git a/src/pkg/runtime/darwin/386/sys.s b/src/pkg/runtime/darwin/386/sys.s index 7961e369c..9d2caca0a 100644 --- a/src/pkg/runtime/darwin/386/sys.s +++ b/src/pkg/runtime/darwin/386/sys.s @@ -80,33 +80,34 @@ TEXT runtime·sigtramp(SB),7,$40 get_tls(CX) // save g - MOVL g(CX), BP - MOVL BP, 20(SP) + MOVL g(CX), DI + MOVL DI, 20(SP) // g = m->gsignal MOVL m(CX), BP MOVL m_gsignal(BP), BP MOVL BP, g(CX) - MOVL handler+0(FP), DI - // 4(FP) is sigstyle - MOVL signo+8(FP), AX - MOVL siginfo+12(FP), BX - MOVL context+16(FP), CX - - MOVL AX, 0(SP) + // copy arguments to sighandler + MOVL sig+8(FP), BX + MOVL BX, 0(SP) + MOVL info+12(FP), BX MOVL BX, 4(SP) - MOVL CX, 8(SP) - CALL DI + MOVL context+16(FP), BX + MOVL BX, 8(SP) + MOVL DI, 12(SP) + + MOVL handler+0(FP), BX + CALL BX // restore g get_tls(CX) - MOVL 20(SP), BP - MOVL BP, g(CX) + MOVL 20(SP), DI + MOVL DI, g(CX) + // call sigreturn MOVL context+16(FP), CX MOVL style+4(FP), BX - MOVL $0, 0(SP) // "caller PC" - ignored MOVL CX, 4(SP) MOVL BX, 8(SP) diff --git a/src/pkg/runtime/darwin/amd64/signal.c b/src/pkg/runtime/darwin/amd64/signal.c index 948b6c9c2..402ab33ca 100644 --- a/src/pkg/runtime/darwin/amd64/signal.c +++ b/src/pkg/runtime/darwin/amd64/signal.c @@ -42,12 +42,11 @@ runtime·signame(int32 sig) } void -runtime·sighandler(int32 sig, Siginfo *info, void *context) +runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) { Ucontext *uc; Mcontext *mc; Regs *r; - G *gp; uintptr *sp; byte *pc; @@ -55,7 +54,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context) mc = uc->uc_mcontext; r = &mc->ss; - if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) { + if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) { // Work around Leopard bug that doesn't set FPE_INTDIV. // Look at instruction to see if it is a divide. // Not necessary in Snow Leopard (si_code will be != 0). @@ -113,12 +112,11 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context) runtime·printf("\n"); if(runtime·gotraceback()){ - runtime·traceback((void*)r->rip, (void*)r->rsp, 0, g); - runtime·tracebackothers(g); + runtime·traceback((void*)r->rip, (void*)r->rsp, 0, gp); + runtime·tracebackothers(gp); runtime·dumpregs(r); } - runtime·breakpoint(); runtime·exit(2); } diff --git a/src/pkg/runtime/darwin/amd64/sys.s b/src/pkg/runtime/darwin/amd64/sys.s index bc970156a..4f9e0d77a 100644 --- a/src/pkg/runtime/darwin/amd64/sys.s +++ b/src/pkg/runtime/darwin/amd64/sys.s @@ -66,8 +66,8 @@ TEXT runtime·sigtramp(SB),7,$64 get_tls(BX) // save g - MOVQ g(BX), BP - MOVQ BP, 40(SP) + MOVQ g(BX), R10 + MOVQ R10, 48(SP) // g = m->gsignal MOVQ m(BX), BP @@ -77,18 +77,21 @@ TEXT runtime·sigtramp(SB),7,$64 MOVL DX, 0(SP) MOVQ CX, 8(SP) MOVQ R8, 16(SP) - MOVQ R8, 24(SP) // save ucontext - MOVQ SI, 32(SP) // save infostyle + MOVQ R10, 24(SP) + + MOVQ R8, 32(SP) // save ucontext + MOVQ SI, 40(SP) // save infostyle CALL DI // restore g get_tls(BX) - MOVQ 40(SP), BP - MOVQ BP, g(BX) + MOVQ 48(SP), R10 + MOVQ R10, g(BX) + // call sigreturn MOVL $(0x2000000+184), AX // sigreturn(ucontext, infostyle) - MOVQ 24(SP), DI // saved ucontext - MOVQ 32(SP), SI // saved infostyle + MOVQ 32(SP), DI // saved ucontext + MOVQ 40(SP), SI // saved infostyle SYSCALL INT $3 // not reached diff --git a/src/pkg/runtime/darwin/thread.c b/src/pkg/runtime/darwin/thread.c index 57e813109..235d69abf 100644 --- a/src/pkg/runtime/darwin/thread.c +++ b/src/pkg/runtime/darwin/thread.c @@ -5,6 +5,7 @@ #include "runtime.h" #include "defs.h" #include "os.h" +#include "stack.h" extern SigTab runtime·sigtab[]; @@ -176,7 +177,7 @@ runtime·minit(void) { // Initialize signal handling. m->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K - runtime·signalstack(m->gsignal->stackguard, 32*1024); + runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024); } // Mach IPC, to get at semaphores diff --git a/src/pkg/runtime/freebsd/386/signal.c b/src/pkg/runtime/freebsd/386/signal.c index ddb11fc3b..8e9d74256 100644 --- a/src/pkg/runtime/freebsd/386/signal.c +++ b/src/pkg/runtime/freebsd/386/signal.c @@ -45,17 +45,16 @@ runtime·signame(int32 sig) } void -runtime·sighandler(int32 sig, Siginfo* info, void* context) +runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) { Ucontext *uc; Mcontext *r; - G *gp; uintptr *sp; uc = context; r = &uc->uc_mcontext; - if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) { + if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) { // Make it look like a call to the signal func. // Have to pass arguments out of band since // augmenting the stack frame would break @@ -99,12 +98,11 @@ runtime·sighandler(int32 sig, Siginfo* info, void* context) runtime·printf("\n"); if(runtime·gotraceback()){ - runtime·traceback((void*)r->mc_eip, (void*)r->mc_esp, 0, m->curg); - runtime·tracebackothers(m->curg); + runtime·traceback((void*)r->mc_eip, (void*)r->mc_esp, 0, gp); + runtime·tracebackothers(gp); runtime·dumpregs(r); } - runtime·breakpoint(); runtime·exit(2); } diff --git a/src/pkg/runtime/freebsd/386/sys.s b/src/pkg/runtime/freebsd/386/sys.s index 7110e6924..60c189bf8 100644 --- a/src/pkg/runtime/freebsd/386/sys.s +++ b/src/pkg/runtime/freebsd/386/sys.s @@ -111,30 +111,36 @@ TEXT runtime·sigaction(SB),7,$-4 CALL runtime·notok(SB) RET -TEXT runtime·sigtramp(SB),7,$40 - // g = m->gsignal - get_tls(DX) - MOVL m(DX), BP - MOVL m_gsignal(BP), BP - MOVL BP, g(DX) +TEXT runtime·sigtramp(SB),7,$44 + get_tls(CX) - MOVL signo+0(FP), AX - MOVL siginfo+4(FP), BX - MOVL context+8(FP), CX + // save g + MOVL g(CX), DI + MOVL DI, 20(SP) + + // g = m->gsignal + MOVL m(CX), BX + MOVL m_gsignal(BX), BX + MOVL BX, g(CX) - MOVL AX, 0(SP) + // copy arguments for call to sighandler + MOVL signo+0(FP), BX + MOVL BX, 0(SP) + MOVL info+4(FP), BX MOVL BX, 4(SP) - MOVL CX, 8(SP) - CALL runtime·sighandler(SB) + MOVL context+8(FP), BX + MOVL BX, 8(SP) + MOVL DI, 12(SP) - // g = m->curg - get_tls(DX) - MOVL m(DX), BP - MOVL m_curg(BP), BP - MOVL BP, g(DX) + CALL runtime·sighandler(SB) + // restore g + get_tls(CX) + MOVL 20(SP), BX + MOVL BX, g(CX) + + // call sigreturn MOVL context+8(FP), AX - MOVL $0, 0(SP) // syscall gap MOVL AX, 4(SP) MOVL $417, AX // sigreturn(ucontext) diff --git a/src/pkg/runtime/freebsd/amd64/signal.c b/src/pkg/runtime/freebsd/amd64/signal.c index 9f873d276..f145371b4 100644 --- a/src/pkg/runtime/freebsd/amd64/signal.c +++ b/src/pkg/runtime/freebsd/amd64/signal.c @@ -53,17 +53,16 @@ runtime·signame(int32 sig) } void -runtime·sighandler(int32 sig, Siginfo* info, void* context) +runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) { Ucontext *uc; Mcontext *r; - G *gp; uintptr *sp; uc = context; r = &uc->uc_mcontext; - if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) { + if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) { // Make it look like a call to the signal func. // Have to pass arguments out of band since // augmenting the stack frame would break @@ -107,12 +106,11 @@ runtime·sighandler(int32 sig, Siginfo* info, void* context) runtime·printf("\n"); if(runtime·gotraceback()){ - runtime·traceback((void*)r->mc_rip, (void*)r->mc_rsp, 0, g); - runtime·tracebackothers(g); + runtime·traceback((void*)r->mc_rip, (void*)r->mc_rsp, 0, gp); + runtime·tracebackothers(gp); runtime·dumpregs(r); } - runtime·breakpoint(); runtime·exit(2); } diff --git a/src/pkg/runtime/freebsd/amd64/sys.s b/src/pkg/runtime/freebsd/amd64/sys.s index b9cf3832d..d986e9ac0 100644 --- a/src/pkg/runtime/freebsd/amd64/sys.s +++ b/src/pkg/runtime/freebsd/amd64/sys.s @@ -90,15 +90,29 @@ TEXT runtime·sigaction(SB),7,$-8 CALL runtime·notok(SB) RET -TEXT runtime·sigtramp(SB),7,$24-16 - get_tls(CX) - MOVQ m(CX), AX - MOVQ m_gsignal(AX), AX - MOVQ AX, g(CX) +TEXT runtime·sigtramp(SB),7,$64 + get_tls(BX) + + // save g + MOVQ g(BX), R10 + MOVQ R10, 40(SP) + + // g = m->signal + MOVQ m(BX), BP + MOVQ m_gsignal(BP), BP + MOVQ BP, g(BX) + MOVQ DI, 0(SP) MOVQ SI, 8(SP) MOVQ DX, 16(SP) + MOVQ R10, 24(SP) + CALL runtime·sighandler(SB) + + // restore g + get_tls(BX) + MOVQ 40(SP), R10 + MOVQ R10, g(BX) RET TEXT runtime·mmap(SB),7,$0 diff --git a/src/pkg/runtime/freebsd/thread.c b/src/pkg/runtime/freebsd/thread.c index 9bd883833..569098aa2 100644 --- a/src/pkg/runtime/freebsd/thread.c +++ b/src/pkg/runtime/freebsd/thread.c @@ -4,6 +4,7 @@ #include "runtime.h" #include "defs.h" #include "os.h" +#include "stack.h" extern SigTab runtime·sigtab[]; extern int32 runtime·sys_umtx_op(uint32*, int32, uint32, void*, void*); @@ -175,7 +176,7 @@ runtime·minit(void) { // Initialize signal handling m->gsignal = runtime·malg(32*1024); - runtime·signalstack(m->gsignal->stackguard, 32*1024); + runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024); } void diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.c index f0d5ce90a..e50cefd9a 100644 --- a/src/pkg/runtime/hashmap.c +++ b/src/pkg/runtime/hashmap.c @@ -781,6 +781,9 @@ runtime·mapaccess(Hmap *h, byte *ak, byte *av, bool *pres) { byte *res; + if(h == nil) + runtime·panicstring("lookup in nil map"); + if(runtime·gcwaiting) runtime·gosched(); @@ -802,6 +805,9 @@ runtime·mapaccess1(Hmap *h, ...) byte *ak, *av; bool pres; + if(h == nil) + runtime·panicstring("lookup in nil map"); + ak = (byte*)&h + h->ko1; av = (byte*)&h + h->vo1; @@ -827,6 +833,9 @@ runtime·mapaccess2(Hmap *h, ...) { byte *ak, *av, *ap; + if(h == nil) + runtime·panicstring("lookup in nil map"); + ak = (byte*)&h + h->ko1; av = (byte*)&h + h->vo1; ap = (byte*)&h + h->po1; @@ -852,6 +861,9 @@ runtime·mapassign(Hmap *h, byte *ak, byte *av) byte *res; int32 hit; + if(h == nil) + runtime·panicstring("assignment to entry in nil map"); + if(runtime·gcwaiting) runtime·gosched(); @@ -889,6 +901,9 @@ runtime·mapassign1(Hmap *h, ...) { byte *ak, *av; + if(h == nil) + runtime·panicstring("assignment to entry in nil map"); + ak = (byte*)&h + h->ko2; av = (byte*)&h + h->vo2; @@ -902,6 +917,9 @@ runtime·mapassign2(Hmap *h, ...) { byte *ak, *av, *ap; + if(h == nil) + runtime·panicstring("assignment to entry in nil map"); + ak = (byte*)&h + h->ko2; av = (byte*)&h + h->vo2; ap = (byte*)&h + h->po2; diff --git a/src/pkg/runtime/iface.c b/src/pkg/runtime/iface.c index 3dec45e2b..698aead3d 100644 --- a/src/pkg/runtime/iface.c +++ b/src/pkg/runtime/iface.c @@ -209,16 +209,25 @@ runtime·convT2E(Type *t, ...) copyin(t, elem, &ret->data); } +static void assertI2Tret(Type *t, Iface i, byte *ret); + // func ifaceI2T(typ *byte, iface any) (ret any) #pragma textflag 7 void runtime·assertI2T(Type *t, Iface i, ...) { - Itab *tab; byte *ret; - Eface err; ret = (byte*)(&i+1); + assertI2Tret(t, i, ret); +} + +static void +assertI2Tret(Type *t, Iface i, byte *ret) +{ + Itab *tab; + Eface err; + tab = i.tab; if(tab == nil) { runtime·newTypeAssertionError(nil, nil, t, @@ -258,15 +267,23 @@ runtime·assertI2T2(Type *t, Iface i, ...) copyout(t, &i.data, ret); } +static void assertE2Tret(Type *t, Eface e, byte *ret); + // func ifaceE2T(typ *byte, iface any) (ret any) #pragma textflag 7 void runtime·assertE2T(Type *t, Eface e, ...) { byte *ret; - Eface err; ret = (byte*)(&e+1); + assertE2Tret(t, e, ret); +} + +static void +assertE2Tret(Type *t, Eface e, byte *ret) +{ + Eface err; if(e.type == nil) { runtime·newTypeAssertionError(nil, nil, t, @@ -307,7 +324,6 @@ runtime·assertE2T2(Type *t, Eface e, ...) } // func convI2E(elem any) (ret any) -#pragma textflag 7 void runtime·convI2E(Iface i, Eface ret) { @@ -322,7 +338,6 @@ runtime·convI2E(Iface i, Eface ret) } // func ifaceI2E(typ *byte, iface any) (ret any) -#pragma textflag 7 void runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret) { @@ -343,7 +358,6 @@ runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret) } // func ifaceI2E2(typ *byte, iface any) (ret any, ok bool) -#pragma textflag 7 void runtime·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok) { @@ -364,7 +378,6 @@ runtime·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok) } // func convI2I(typ *byte, elem any) (ret any) -#pragma textflag 7 void runtime·convI2I(InterfaceType* inter, Iface i, Iface ret) { @@ -399,7 +412,6 @@ runtime·ifaceI2I(InterfaceType *inter, Iface i, Iface *ret) } // func ifaceI2I(sigi *byte, iface any) (ret any) -#pragma textflag 7 void runtime·assertI2I(InterfaceType* inter, Iface i, Iface ret) { @@ -407,7 +419,6 @@ runtime·assertI2I(InterfaceType* inter, Iface i, Iface ret) } // func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool) -#pragma textflag 7 void runtime·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok) { @@ -446,7 +457,6 @@ runtime·ifaceE2I(InterfaceType *inter, Eface e, Iface *ret) } // func ifaceE2I(sigi *byte, iface any) (ret any) -#pragma textflag 7 void runtime·assertE2I(InterfaceType* inter, Eface e, Iface ret) { @@ -454,7 +464,6 @@ runtime·assertE2I(InterfaceType* inter, Eface e, Iface ret) } // ifaceE2I2(sigi *byte, iface any) (ret any, ok bool) -#pragma textflag 7 void runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok) { @@ -474,7 +483,6 @@ runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok) } // func ifaceE2E(typ *byte, iface any) (ret any) -#pragma textflag 7 void runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret) { @@ -494,7 +502,6 @@ runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret) } // func ifaceE2E2(iface any) (ret any, ok bool) -#pragma textflag 7 void runtime·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok) { diff --git a/src/pkg/runtime/linux/386/signal.c b/src/pkg/runtime/linux/386/signal.c index 9651a6f28..bd918c7ea 100644 --- a/src/pkg/runtime/linux/386/signal.c +++ b/src/pkg/runtime/linux/386/signal.c @@ -42,17 +42,16 @@ runtime·signame(int32 sig) } void -runtime·sighandler(int32 sig, Siginfo* info, void* context) +runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) { Ucontext *uc; Sigcontext *r; uintptr *sp; - G *gp; uc = context; r = &uc->uc_mcontext; - if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) { + if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) { // Make it look like a call to the signal func. // Have to pass arguments out of band since // augmenting the stack frame would break @@ -96,12 +95,11 @@ runtime·sighandler(int32 sig, Siginfo* info, void* context) runtime·printf("\n"); if(runtime·gotraceback()){ - runtime·traceback((void*)r->eip, (void*)r->esp, 0, m->curg); - runtime·tracebackothers(m->curg); + runtime·traceback((void*)r->eip, (void*)r->esp, 0, gp); + runtime·tracebackothers(gp); runtime·dumpregs(r); } - runtime·breakpoint(); runtime·exit(2); } diff --git a/src/pkg/runtime/linux/386/sys.s b/src/pkg/runtime/linux/386/sys.s index a1505b0b0..a684371be 100644 --- a/src/pkg/runtime/linux/386/sys.s +++ b/src/pkg/runtime/linux/386/sys.s @@ -56,12 +56,12 @@ TEXT runtime·rt_sigaction(SB),7,$0 INT $0x80 RET -TEXT runtime·sigtramp(SB),7,$40 +TEXT runtime·sigtramp(SB),7,$44 get_tls(CX) // save g - MOVL g(CX), BX - MOVL BX, 20(SP) + MOVL g(CX), DI + MOVL DI, 20(SP) // g = m->gsignal MOVL m(CX), BX @@ -75,6 +75,7 @@ TEXT runtime·sigtramp(SB),7,$40 MOVL BX, 4(SP) MOVL context+8(FP), BX MOVL BX, 8(SP) + MOVL DI, 12(SP) CALL runtime·sighandler(SB) diff --git a/src/pkg/runtime/linux/amd64/signal.c b/src/pkg/runtime/linux/amd64/signal.c index 9e501c96d..ea0932523 100644 --- a/src/pkg/runtime/linux/amd64/signal.c +++ b/src/pkg/runtime/linux/amd64/signal.c @@ -50,19 +50,18 @@ runtime·signame(int32 sig) } void -runtime·sighandler(int32 sig, Siginfo* info, void* context) +runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) { Ucontext *uc; Mcontext *mc; Sigcontext *r; uintptr *sp; - G *gp; uc = context; mc = &uc->uc_mcontext; r = (Sigcontext*)mc; // same layout, more conveient names - if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) { + if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) { // Make it look like a call to the signal func. // Have to pass arguments out of band since // augmenting the stack frame would break @@ -106,12 +105,11 @@ runtime·sighandler(int32 sig, Siginfo* info, void* context) runtime·printf("\n"); if(runtime·gotraceback()){ - runtime·traceback((void*)r->rip, (void*)r->rsp, 0, g); - runtime·tracebackothers(g); + runtime·traceback((void*)r->rip, (void*)r->rsp, 0, gp); + runtime·tracebackothers(gp); runtime·dumpregs(r); } - runtime·breakpoint(); runtime·exit(2); } diff --git a/src/pkg/runtime/linux/amd64/sys.s b/src/pkg/runtime/linux/amd64/sys.s index 170b659fc..1bf734dc0 100644 --- a/src/pkg/runtime/linux/amd64/sys.s +++ b/src/pkg/runtime/linux/amd64/sys.s @@ -64,8 +64,8 @@ TEXT runtime·sigtramp(SB),7,$64 get_tls(BX) // save g - MOVQ g(BX), BP - MOVQ BP, 40(SP) + MOVQ g(BX), R10 + MOVQ R10, 40(SP) // g = m->gsignal MOVQ m(BX), BP @@ -75,12 +75,14 @@ TEXT runtime·sigtramp(SB),7,$64 MOVQ DI, 0(SP) MOVQ SI, 8(SP) MOVQ DX, 16(SP) + MOVQ R10, 24(SP) + CALL runtime·sighandler(SB) // restore g get_tls(BX) - MOVQ 40(SP), BP - MOVQ BP, g(BX) + MOVQ 40(SP), R10 + MOVQ R10, g(BX) RET TEXT runtime·sigignore(SB),7,$0 diff --git a/src/pkg/runtime/linux/arm/signal.c b/src/pkg/runtime/linux/arm/signal.c index 481bd13c6..843c40b68 100644 --- a/src/pkg/runtime/linux/arm/signal.c +++ b/src/pkg/runtime/linux/arm/signal.c @@ -50,16 +50,15 @@ runtime·signame(int32 sig) } void -runtime·sighandler(int32 sig, Siginfo *info, void *context) +runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) { Ucontext *uc; Sigcontext *r; - G *gp; uc = context; r = &uc->uc_mcontext; - if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) { + if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) { // Make it look like a call to the signal func. // Have to pass arguments out of band since // augmenting the stack frame would break @@ -99,8 +98,8 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context) runtime·printf("\n"); if(runtime·gotraceback()){ - runtime·traceback((void*)r->arm_pc, (void*)r->arm_sp, (void*)r->arm_lr, m->curg); - runtime·tracebackothers(m->curg); + runtime·traceback((void*)r->arm_pc, (void*)r->arm_sp, (void*)r->arm_lr, gp); + runtime·tracebackothers(gp); runtime·printf("\n"); runtime·dumpregs(r); } diff --git a/src/pkg/runtime/linux/arm/sys.s b/src/pkg/runtime/linux/arm/sys.s index b25cf81aa..9daf9c2e4 100644 --- a/src/pkg/runtime/linux/arm/sys.s +++ b/src/pkg/runtime/linux/arm/sys.s @@ -197,11 +197,24 @@ TEXT runtime·sigignore(SB),7,$0 RET TEXT runtime·sigtramp(SB),7,$24 + // save g + MOVW g, R3 + MOVW g, 20(R13) + + // g = m->gsignal MOVW m_gsignal(m), g + + // copy arguments for call to sighandler MOVW R0, 4(R13) MOVW R1, 8(R13) MOVW R2, 12(R13) + MOVW R3, 16(R13) + BL runtime·sighandler(SB) + + // restore g + MOVW 20(R13), g + RET TEXT runtime·rt_sigaction(SB),7,$0 @@ -217,3 +230,21 @@ TEXT runtime·sigreturn(SB),7,$0 MOVW $SYS_rt_sigreturn, R7 SWI $0 RET + +// Use kernel version instead of native armcas in ../../arm.s. +// See ../../../sync/atomic/asm_linux_arm.s for details. +TEXT cas<>(SB),7,$0 + MOVW $0xffff0fc0, PC + +TEXT runtime·cas(SB),7,$0 + MOVW valptr+0(FP), R2 + MOVW old+4(FP), R0 + MOVW new+8(FP), R1 + BL cas<>(SB) + MOVW $0, R0 + MOVW.CS $1, R0 + RET + +TEXT runtime·casp(SB),7,$0 + B runtime·cas(SB) + diff --git a/src/pkg/runtime/linux/thread.c b/src/pkg/runtime/linux/thread.c index d5f9a8fb0..7166b0ef2 100644 --- a/src/pkg/runtime/linux/thread.c +++ b/src/pkg/runtime/linux/thread.c @@ -5,6 +5,7 @@ #include "runtime.h" #include "defs.h" #include "os.h" +#include "stack.h" extern SigTab runtime·sigtab[]; @@ -274,7 +275,7 @@ runtime·minit(void) { // Initialize signal handling. m->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K - runtime·signalstack(m->gsignal->stackguard, 32*1024); + runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024); } void diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc index 70b85d68d..41060682e 100644 --- a/src/pkg/runtime/malloc.goc +++ b/src/pkg/runtime/malloc.goc @@ -8,6 +8,7 @@ package runtime #include "runtime.h" +#include "stack.h" #include "malloc.h" #include "defs.h" #include "type.h" @@ -146,6 +147,9 @@ runtime·free(void *v) // Large object. size = s->npages<<PageShift; *(uintptr*)(s->start<<PageShift) = 1; // mark as "needs to be zeroed" + // Must mark v freed before calling unmarkspan and MHeap_Free: + // they might coalesce v into other spans and change the bitmap further. + runtime·markfreed(v, size); runtime·unmarkspan(v, 1<<PageShift); runtime·MHeap_Free(&runtime·mheap, s, 1); } else { @@ -154,10 +158,13 @@ runtime·free(void *v) size = runtime·class_to_size[sizeclass]; if(size > sizeof(uintptr)) ((uintptr*)v)[1] = 1; // mark as "needs to be zeroed" + // Must mark v freed before calling MCache_Free: + // it might coalesce v and other blocks into a bigger span + // and change the bitmap further. + runtime·markfreed(v, size); mstats.by_size[sizeclass].nfree++; runtime·MCache_Free(c, v, sizeclass, size); } - runtime·markfreed(v, size); mstats.alloc -= size; if(prof) runtime·MProf_Free(v, size); @@ -379,7 +386,7 @@ static struct { } stacks; enum { - FixedStack = StackBig + StackExtra + FixedStack = StackMin, }; void* @@ -387,6 +394,12 @@ runtime·stackalloc(uint32 n) { void *v; + // Stackalloc must be called on scheduler stack, so that we + // never try to grow the stack during the code that stackalloc runs. + // Doing so would cause a deadlock (issue 1547). + if(g != m->g0) + runtime·throw("stackalloc not on scheduler stack"); + if(m->mallocing || m->gcing || n == FixedStack) { runtime·lock(&stacks); if(stacks.size == 0) diff --git a/src/pkg/runtime/mfinal.c b/src/pkg/runtime/mfinal.c index 03ee777c0..f3138145b 100644 --- a/src/pkg/runtime/mfinal.c +++ b/src/pkg/runtime/mfinal.c @@ -5,7 +5,9 @@ #include "runtime.h" #include "malloc.h" -// TODO(rsc): Why not just use mheap.Lock? +// Lock to protect finalizer data structures. +// Cannot reuse mheap.Lock because the finalizer +// maintenance requires allocation. static Lock finlock; // Finalizer hash table. Direct hash, linear scan, at most 3/4 full. @@ -90,7 +92,6 @@ runtime·addfinalizer(void *p, void (*f)(void*), int32 nret) { Fintab newtab; int32 i; - uint32 *ref; byte *base; Finalizer *e; diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index 232c6cdcd..7c175b308 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -380,6 +380,7 @@ mark(void) break; case Grunning: case Grecovery: + case Gstackalloc: if(gp != g) runtime·throw("mark - world not stopped"); scanstack(gp); @@ -584,7 +585,7 @@ runtime·gc(int32 force) if(fp != nil) { // kick off or wake up goroutine to run queued finalizers if(fing == nil) - fing = runtime·newproc1((byte*)runfinq, nil, 0, 0); + fing = runtime·newproc1((byte*)runfinq, nil, 0, 0, runtime·gc); else if(fingwait) { fingwait = 0; runtime·ready(fing); @@ -663,7 +664,7 @@ runfinq(void) void runtime·markallocated(void *v, uintptr n, bool noptr) { - uintptr *b, bits, off, shift; + uintptr *b, obits, bits, off, shift; if(0) runtime·printf("markallocated %p+%p\n", v, n); @@ -675,17 +676,27 @@ runtime·markallocated(void *v, uintptr n, bool noptr) b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; shift = off % wordsPerBitmapWord; - bits = (*b & ~(bitMask<<shift)) | (bitAllocated<<shift); - if(noptr) - bits |= bitNoPointers<<shift; - *b = bits; + for(;;) { + obits = *b; + bits = (obits & ~(bitMask<<shift)) | (bitAllocated<<shift); + if(noptr) + bits |= bitNoPointers<<shift; + if(runtime·gomaxprocs == 1) { + *b = bits; + break; + } else { + // gomaxprocs > 1: use atomic op + if(runtime·casp((void**)b, (void*)obits, (void*)bits)) + break; + } + } } // mark the block at v of size n as freed. void runtime·markfreed(void *v, uintptr n) { - uintptr *b, off, shift; + uintptr *b, obits, bits, off, shift; if(0) runtime·printf("markallocated %p+%p\n", v, n); @@ -697,7 +708,18 @@ runtime·markfreed(void *v, uintptr n) b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; shift = off % wordsPerBitmapWord; - *b = (*b & ~(bitMask<<shift)) | (bitBlockBoundary<<shift); + for(;;) { + obits = *b; + bits = (obits & ~(bitMask<<shift)) | (bitBlockBoundary<<shift); + if(runtime·gomaxprocs == 1) { + *b = bits; + break; + } else { + // gomaxprocs > 1: use atomic op + if(runtime·casp((void**)b, (void*)obits, (void*)bits)) + break; + } + } } // check that the block at v of size n is marked freed. @@ -739,6 +761,10 @@ runtime·markspan(void *v, uintptr size, uintptr n, bool leftover) if(leftover) // mark a boundary just past end of last block too n++; for(; n-- > 0; p += size) { + // Okay to use non-atomic ops here, because we control + // the entire span, and each bitmap word has bits for only + // one span, so no other goroutines are changing these + // bitmap words. off = (uintptr*)p - (uintptr*)runtime·mheap.arena_start; // word offset b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; shift = off % wordsPerBitmapWord; @@ -763,6 +789,10 @@ runtime·unmarkspan(void *v, uintptr n) n /= PtrSize; if(n%wordsPerBitmapWord != 0) runtime·throw("unmarkspan: unaligned length"); + // Okay to use non-atomic ops here, because we control + // the entire span, and each bitmap word has bits for only + // one span, so no other goroutines are changing these + // bitmap words. n /= wordsPerBitmapWord; while(n-- > 0) *b-- = 0; @@ -783,13 +813,24 @@ runtime·blockspecial(void *v) void runtime·setblockspecial(void *v) { - uintptr *b, off, shift; + uintptr *b, off, shift, bits, obits; off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; shift = off % wordsPerBitmapWord; - *b |= bitSpecial<<shift; + for(;;) { + obits = *b; + bits = obits | (bitSpecial<<shift); + if(runtime·gomaxprocs == 1) { + *b = bits; + break; + } else { + // gomaxprocs > 1: use atomic op + if(runtime·casp((void**)b, (void*)obits, (void*)bits)) + break; + } + } } void diff --git a/src/pkg/runtime/print.c b/src/pkg/runtime/print.c index 3b4bb103d..b8069aa39 100644 --- a/src/pkg/runtime/print.c +++ b/src/pkg/runtime/print.c @@ -42,113 +42,108 @@ runtime·printf(int8 *s, ...) vprintf(s, arg); } -static byte* -vrnd(byte *p, int32 x) -{ - if((uint32)(uintptr)p&(x-1)) - p += x - ((uint32)(uintptr)p&(x-1)); - return p; -} - // Very simple printf. Only for debugging prints. // Do not add to this without checking with Rob. static void -vprintf(int8 *s, byte *arg) +vprintf(int8 *s, byte *base) { int8 *p, *lp; - byte *narg; + uintptr arg, narg; + byte *v; // lock(&debuglock); lp = p = s; + arg = 0; for(; *p; p++) { if(*p != '%') continue; if(p > lp) runtime·write(2, lp, p-lp); p++; - narg = nil; + narg = 0; switch(*p) { case 't': narg = arg + 1; break; case 'd': // 32-bit case 'x': - arg = vrnd(arg, 4); + arg = runtime·rnd(arg, 4); narg = arg + 4; break; case 'D': // 64-bit case 'U': case 'X': case 'f': - arg = vrnd(arg, sizeof(uintptr)); + arg = runtime·rnd(arg, sizeof(uintptr)); narg = arg + 8; break; case 'C': - arg = vrnd(arg, sizeof(uintptr)); + arg = runtime·rnd(arg, sizeof(uintptr)); narg = arg + 16; break; case 'p': // pointer-sized case 's': - arg = vrnd(arg, sizeof(uintptr)); + arg = runtime·rnd(arg, sizeof(uintptr)); narg = arg + sizeof(uintptr); break; case 'S': // pointer-aligned but bigger - arg = vrnd(arg, sizeof(uintptr)); + arg = runtime·rnd(arg, sizeof(uintptr)); narg = arg + sizeof(String); break; case 'a': // pointer-aligned but bigger - arg = vrnd(arg, sizeof(uintptr)); + arg = runtime·rnd(arg, sizeof(uintptr)); narg = arg + sizeof(Slice); break; case 'i': // pointer-aligned but bigger case 'e': - arg = vrnd(arg, sizeof(uintptr)); + arg = runtime·rnd(arg, sizeof(uintptr)); narg = arg + sizeof(Eface); break; } + v = base+arg; switch(*p) { case 'a': - runtime·printslice(*(Slice*)arg); + runtime·printslice(*(Slice*)v); break; case 'd': - runtime·printint(*(int32*)arg); + runtime·printint(*(int32*)v); break; case 'D': - runtime·printint(*(int64*)arg); + runtime·printint(*(int64*)v); break; case 'e': - runtime·printeface(*(Eface*)arg); + runtime·printeface(*(Eface*)v); break; case 'f': - runtime·printfloat(*(float64*)arg); + runtime·printfloat(*(float64*)v); break; case 'C': - runtime·printcomplex(*(Complex128*)arg); + runtime·printcomplex(*(Complex128*)v); break; case 'i': - runtime·printiface(*(Iface*)arg); + runtime·printiface(*(Iface*)v); break; case 'p': - runtime·printpointer(*(void**)arg); + runtime·printpointer(*(void**)v); break; case 's': - runtime·prints(*(int8**)arg); + runtime·prints(*(int8**)v); break; case 'S': - runtime·printstring(*(String*)arg); + runtime·printstring(*(String*)v); break; case 't': - runtime·printbool(*(bool*)arg); + runtime·printbool(*(bool*)v); break; case 'U': - runtime·printuint(*(uint64*)arg); + runtime·printuint(*(uint64*)v); break; case 'x': - runtime·printhex(*(uint32*)arg); + runtime·printhex(*(uint32*)v); break; case 'X': - runtime·printhex(*(uint64*)arg); + runtime·printhex(*(uint64*)v); break; } arg = narg; diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index 26c1f13a4..db6072b5c 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -7,6 +7,7 @@ #include "defs.h" #include "malloc.h" #include "os.h" +#include "stack.h" bool runtime·iscgo; @@ -63,7 +64,6 @@ struct Sched { int32 mcount; // number of ms that have been created int32 mcpu; // number of ms executing on cpu int32 mcpumax; // max number of ms allowed on cpu - int32 gomaxprocs; int32 msyscall; // number of ms in system calls int32 predawn; // running initialization, don't run new gs. @@ -73,6 +73,7 @@ struct Sched { }; Sched runtime·sched; +int32 gomaxprocs; // Scheduling helpers. Sched must be locked. static void gput(G*); // put/get on ghead/gtail @@ -116,13 +117,13 @@ runtime·schedinit(void) // For debugging: // Allocate internal symbol table representation now, // so that we don't need to call malloc when we crash. - // findfunc(0); + // runtime·findfunc(0); - runtime·sched.gomaxprocs = 1; + runtime·gomaxprocs = 1; p = runtime·getenv("GOMAXPROCS"); if(p != nil && (n = runtime·atoi(p)) != 0) - runtime·sched.gomaxprocs = n; - runtime·sched.mcpumax = runtime·sched.gomaxprocs; + runtime·gomaxprocs = n; + runtime·sched.mcpumax = runtime·gomaxprocs; runtime·sched.mcount = 1; runtime·sched.predawn = 1; @@ -165,6 +166,18 @@ runtime·tracebackothers(G *me) } } +// Mark this g as m's idle goroutine. +// This functionality might be used in environments where programs +// are limited to a single thread, to simulate a select-driven +// network server. It is not exposed via the standard runtime API. +void +runtime·idlegoroutine(void) +{ + if(g->idlem != nil) + runtime·throw("g is already an idle goroutine"); + g->idlem = m; +} + // Put on `g' queue. Sched must be locked. static void gput(G *g) @@ -176,6 +189,18 @@ gput(G *g) mnextg(m, g); return; } + + // If g is the idle goroutine for an m, hand it off. + if(g->idlem != nil) { + if(g->idlem->idleg != nil) { + runtime·printf("m%d idle out of sync: g%d g%d\n", + g->idlem->id, + g->idlem->idleg->goid, g->goid); + runtime·throw("runtime: double idle"); + } + g->idlem->idleg = g; + return; + } g->schedlink = nil; if(runtime·sched.ghead == nil) @@ -198,6 +223,9 @@ gget(void) if(runtime·sched.ghead == nil) runtime·sched.gtail = nil; runtime·sched.gwait--; + } else if(m->idleg != nil) { + g = m->idleg; + m->idleg = nil; } return g; } @@ -252,8 +280,10 @@ readylocked(G *g) } // Mark runnable. - if(g->status == Grunnable || g->status == Grunning || g->status == Grecovery) + if(g->status == Grunnable || g->status == Grunning || g->status == Grecovery || g->status == Gstackalloc) { + runtime·printf("goroutine %d has status %d\n", g->goid, g->status); runtime·throw("bad g->status in ready"); + } g->status = Grunnable; gput(g); @@ -376,7 +406,7 @@ runtime·starttheworld(void) { runtime·lock(&runtime·sched); runtime·gcwaiting = 0; - runtime·sched.mcpumax = runtime·sched.gomaxprocs; + runtime·sched.mcpumax = runtime·gomaxprocs; matchmg(); runtime·unlock(&runtime·sched); } @@ -491,6 +521,13 @@ scheduler(void) runtime·free(d); runtime·gogo(&gp->sched, 1); } + + if(gp->status == Gstackalloc) { + // switched to scheduler stack to call stackalloc. + gp->param = runtime·stackalloc((uintptr)gp->param); + gp->status = Grunning; + runtime·gogo(&gp->sched, 1); + } // Jumped here via runtime·gosave/gogo, so didn't // execute lock(&runtime·sched) above. @@ -508,6 +545,8 @@ scheduler(void) switch(gp->status){ case Grunnable: case Gdead: + case Grecovery: + case Gstackalloc: // Shouldn't have been running! runtime·throw("bad gp->status in sched"); case Grunning: @@ -520,6 +559,7 @@ scheduler(void) gp->lockedm = nil; m->lockedg = nil; } + gp->idlem = nil; unwindstack(gp, nil); gfput(gp); if(--runtime·sched.gcount == 0) @@ -701,7 +741,7 @@ runtime·oldstack(void) goid = old.gobuf.g->goid; // fault if g is bad, before gogo if(old.free != 0) - runtime·stackfree(g1->stackguard - StackGuard, old.free); + runtime·stackfree(g1->stackguard - StackGuard - StackSystem, old.free); g1->stackbase = old.stackbase; g1->stackguard = old.stackguard; @@ -739,14 +779,15 @@ runtime·newstack(void) // the new Stktop* is necessary to unwind, but // we don't need to create a new segment. top = (Stktop*)(m->morebuf.sp - sizeof(*top)); - stk = g1->stackguard - StackGuard; + stk = g1->stackguard - StackGuard - StackSystem; free = 0; } else { // allocate new segment. framesize += argsize; - if(framesize < StackBig) - framesize = StackBig; framesize += StackExtra; // room for more functions, Stktop. + if(framesize < StackMin) + framesize = StackMin; + framesize += StackSystem; stk = runtime·stackalloc(framesize); top = (Stktop*)(stk+framesize-sizeof(*top)); free = framesize; @@ -767,7 +808,7 @@ runtime·newstack(void) g1->ispanic = false; g1->stackbase = (byte*)top; - g1->stackguard = stk + StackGuard; + g1->stackguard = stk + StackGuard + StackSystem; sp = (byte*)top; if(argsize > 0) { @@ -793,18 +834,35 @@ runtime·newstack(void) G* runtime·malg(int32 stacksize) { - G *g; + G *newg; byte *stk; + int32 oldstatus; - g = runtime·malloc(sizeof(G)); + newg = runtime·malloc(sizeof(G)); if(stacksize >= 0) { - stk = runtime·stackalloc(stacksize + StackGuard); - g->stack0 = stk; - g->stackguard = stk + StackGuard; - g->stackbase = stk + StackGuard + stacksize - sizeof(Stktop); - runtime·memclr(g->stackbase, sizeof(Stktop)); + if(g == m->g0) { + // running on scheduler stack already. + stk = runtime·stackalloc(StackSystem + stacksize); + } else { + // have to call stackalloc on scheduler stack. + oldstatus = g->status; + g->param = (void*)(StackSystem + stacksize); + g->status = Gstackalloc; + // next two lines are runtime·gosched without the check + // of m->locks. we're almost certainly holding a lock, + // but this is not a real rescheduling so it's okay. + if(runtime·gosave(&g->sched) == 0) + runtime·gogo(&m->sched, 1); + stk = g->param; + g->param = nil; + g->status = oldstatus; + } + newg->stack0 = stk; + newg->stackguard = stk + StackSystem + StackGuard; + newg->stackbase = stk + StackSystem + stacksize - sizeof(Stktop); + runtime·memclr(newg->stackbase, sizeof(Stktop)); } - return g; + return newg; } /* @@ -826,11 +884,11 @@ runtime·newproc(int32 siz, byte* fn, ...) argp = (byte*)(&fn+2); // skip caller's saved LR else argp = (byte*)(&fn+1); - runtime·newproc1(fn, argp, siz, 0); + runtime·newproc1(fn, argp, siz, 0, runtime·getcallerpc(&siz)); } G* -runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret) +runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret, void *callerpc) { byte *sp; G *newg; @@ -846,10 +904,10 @@ runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret) if((newg = gfget()) != nil){ newg->status = Gwaiting; - if(newg->stackguard - StackGuard != newg->stack0) + if(newg->stackguard - StackGuard - StackSystem != newg->stack0) runtime·throw("invalid stack in newg"); } else { - newg = runtime·malg(StackBig); + newg = runtime·malg(StackMin); newg->status = Gwaiting; newg->alllink = runtime·allg; runtime·allg = newg; @@ -868,6 +926,7 @@ runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret) newg->sched.pc = (byte*)runtime·goexit; newg->sched.g = newg; newg->entry = fn; + newg->gopc = (uintptr)callerpc; runtime·sched.gcount++; runtime·goidgen++; @@ -1019,6 +1078,7 @@ runtime·panic(Eface e) } // ran out of deferred calls - old-school panic now + runtime·startpanic(); printpanics(g->panic); runtime·dopanic(0); } @@ -1098,7 +1158,7 @@ nomatch: static void gfput(G *g) { - if(g->stackguard - StackGuard != g->stack0) + if(g->stackguard - StackGuard - StackSystem != g->stack0) runtime·throw("invalid stack in gfput"); g->schedlink = runtime·sched.gfree; runtime·sched.gfree = g; @@ -1151,10 +1211,10 @@ runtime·gomaxprocsfunc(int32 n) int32 ret; runtime·lock(&runtime·sched); - ret = runtime·sched.gomaxprocs; + ret = runtime·gomaxprocs; if (n <= 0) n = ret; - runtime·sched.gomaxprocs = n; + runtime·gomaxprocs = n; runtime·sched.mcpumax = n; // handle fewer procs? if(runtime·sched.mcpu > runtime·sched.mcpumax) { diff --git a/src/pkg/runtime/runtime-gdb.py b/src/pkg/runtime/runtime-gdb.py index 677e9bde4..68dd8abdc 100644 --- a/src/pkg/runtime/runtime-gdb.py +++ b/src/pkg/runtime/runtime-gdb.py @@ -13,7 +13,7 @@ path to this file based on the path to the runtime package. # - pretty printing only works for the 'native' strings. E.g. 'type # foo string' will make foo a plain struct in the eyes of gdb, # circumventing the pretty print triggering. -# - + import sys, re @@ -39,7 +39,8 @@ class StringTypePrinter: return 'string' def to_string(self): - return self.val['str'] + l = int(self.val['len']) + return self.val['str'].string("utf-8", "ignore", l) class SliceTypePrinter: diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c index e3a20d48a..1a3653f10 100644 --- a/src/pkg/runtime/runtime.c +++ b/src/pkg/runtime/runtime.c @@ -3,12 +3,13 @@ // license that can be found in the LICENSE file. #include "runtime.h" +#include "stack.h" enum { maxround = sizeof(uintptr), }; -int32 runtime·panicking = 0; +uint32 runtime·panicking; int32 runtime·gotraceback(void) @@ -21,14 +22,24 @@ runtime·gotraceback(void) return runtime·atoi(p); } +static Lock paniclk; + void -runtime·dopanic(int32 unused) +runtime·startpanic(void) { - if(runtime·panicking) { - runtime·printf("double panic\n"); + if(m->dying) { + runtime·printf("panic during panic\n"); runtime·exit(3); } - runtime·panicking++; + m->dying = 1; + runtime·xadd(&runtime·panicking, 1); + runtime·lock(&paniclk); +} + +void +runtime·dopanic(int32 unused) +{ + static bool didothers; if(g->sig != 0) runtime·printf("\n[signal %x code=%p addr=%p pc=%p]\n", @@ -37,10 +48,22 @@ runtime·dopanic(int32 unused) runtime·printf("\n"); if(runtime·gotraceback()){ runtime·traceback(runtime·getcallerpc(&unused), runtime·getcallersp(&unused), 0, g); - runtime·tracebackothers(g); + if(!didothers) { + didothers = true; + runtime·tracebackothers(g); + } } - - runtime·breakpoint(); // so we can grab it in a debugger + runtime·unlock(&paniclk); + if(runtime·xadd(&runtime·panicking, -1) != 0) { + // Some other m is panicking too. + // Let it print what it needs to print. + // Wait forever without chewing up cpu. + // It will exit when it's done. + static Lock deadlock; + runtime·lock(&deadlock); + runtime·lock(&deadlock); + } + runtime·exit(2); } @@ -73,6 +96,7 @@ runtime·throwinit(void) void runtime·throw(int8 *s) { + runtime·startpanic(); runtime·printf("throw: %s\n", s); runtime·dopanic(0); *(int32*)0 = 0; // not reached diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index cea07e4a7..85dca54f7 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -104,6 +104,7 @@ enum Gmoribund, Gdead, Grecovery, + Gstackalloc, }; enum { @@ -196,10 +197,12 @@ struct G bool ispanic; M* m; // for debuggers, but offset not hard-coded M* lockedm; + M* idlem; int32 sig; uintptr sigcode0; uintptr sigcode1; uintptr sigpc; + uintptr gopc; // pc of go statement that created this goroutine }; struct M { @@ -224,6 +227,7 @@ struct M int32 locks; int32 nomemprof; int32 waitnextg; + int32 dying; Note havenextg; G* nextg; M* alllink; // on allm @@ -231,6 +235,7 @@ struct M uint32 machport; // Return address for Mach IPC (OS X) MCache *mcache; G* lockedg; + G* idleg; uint32 freglo[16]; // D[i] lsb and F[i] uint32 freghi[16]; // D[i] msb and F[i+16] uint32 fflag; // floating point compare flags @@ -358,7 +363,7 @@ G* runtime·allg; M* runtime·allm; int32 runtime·goidgen; extern int32 runtime·gomaxprocs; -extern int32 runtime·panicking; +extern uint32 runtime·panicking; extern int32 runtime·gcwaiting; // gc is waiting to run int8* runtime·goos; extern bool runtime·iscgo; @@ -448,13 +453,14 @@ void runtime·entersyscall(void); void runtime·exitsyscall(void); void runtime·startcgocallback(G*); void runtime·endcgocallback(G*); -G* runtime·newproc1(byte*, byte*, int32, int32); +G* runtime·newproc1(byte*, byte*, int32, int32, void*); void runtime·siginit(void); bool runtime·sigsend(int32 sig); void runtime·gettime(int64*, int32*); int32 runtime·callers(int32, uintptr*, int32); int64 runtime·nanotime(void); void runtime·dopanic(int32); +void runtime·startpanic(void); #pragma varargck argpos runtime·printf 1 #pragma varargck type "d" int32 @@ -590,83 +596,17 @@ int32 runtime·chancap(Hchan*); void runtime·ifaceE2I(struct InterfaceType*, Eface, Iface*); -/* - * Stack layout parameters. - * Known to linkers. - * - * The per-goroutine g->stackguard is set to point - * StackGuard bytes above the bottom of the stack. - * Each function compares its stack pointer against - * g->stackguard to check for overflow. To cut one - * instruction from the check sequence for functions - * with tiny frames, the stack is allowed to protrude - * StackSmall bytes below the stack guard. Functions - * with large frames don't bother with the check and - * always call morestack. The sequences are - * (for amd64, others are similar): - * - * guard = g->stackguard - * frame = function's stack frame size - * argsize = size of function arguments (call + return) - * - * stack frame size <= StackSmall: - * CMPQ guard, SP - * JHI 3(PC) - * MOVQ m->morearg, $(argsize << 32) - * CALL morestack(SB) - * - * stack frame size > StackSmall but < StackBig - * LEAQ (frame-StackSmall)(SP), R0 - * CMPQ guard, R0 - * JHI 3(PC) - * MOVQ m->morearg, $(argsize << 32) - * CALL morestack(SB) - * - * stack frame size >= StackBig: - * MOVQ m->morearg, $((argsize << 32) | frame) - * CALL morestack(SB) - * - * The bottom StackGuard - StackSmall bytes are important: - * there has to be enough room to execute functions that - * refuse to check for stack overflow, either because they - * need to be adjacent to the actual caller's frame (deferproc) - * or because they handle the imminent stack overflow (morestack). - * - * For example, deferproc might call malloc, which does one - * of the above checks (without allocating a full frame), - * which might trigger a call to morestack. This sequence - * needs to fit in the bottom section of the stack. On amd64, - * morestack's frame is 40 bytes, and deferproc's frame is 56 bytes. - * That fits well within the StackGuard - StackSmall = 128 bytes - * at the bottom. There may be other sequences lurking or yet to - * be written that require more stack. Morestack checks to make - * sure the stack has not completely overflowed and should catch - * such sequences. - */ enum { + // StackSystem is a number of additional bytes to add + // to each stack below the usual guard area for OS-specific + // purposes like signal handling. + // TODO(rsc): This is only for Windows. Can't Windows use + // a separate exception stack like every other operating system? #ifdef __WINDOWS__ - // need enough room in guard area for exception handler. - // use larger stacks to compensate for larger stack guard. - StackSmall = 256, - StackGuard = 2048, - StackBig = 8192, - StackExtra = StackGuard, + StackSystem = 2048, #else - // byte offset of stack guard (g->stackguard) above bottom of stack. - StackGuard = 256, - - // checked frames are allowed to protrude below the guard by - // this many bytes. this saves an instruction in the checking - // sequence when the stack frame is tiny. - StackSmall = 128, - - // extra space in the frame (beyond the function for which - // the frame is allocated) is assumed not to be much bigger - // than this amount. it may not be used efficiently if it is. - StackBig = 4096, - - // extra room over frame size when allocating a stack. - StackExtra = 1024, + StackSystem = 0, #endif }; + diff --git a/src/pkg/runtime/stack.h b/src/pkg/runtime/stack.h new file mode 100644 index 000000000..ebf0462b5 --- /dev/null +++ b/src/pkg/runtime/stack.h @@ -0,0 +1,86 @@ +// 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. + +/* +Stack layout parameters. +Included both by runtime (compiled via 6c) and linkers (compiled via gcc). + +The per-goroutine g->stackguard is set to point StackGuard bytes +above the bottom of the stack. Each function compares its stack +pointer against g->stackguard to check for overflow. To cut one +instruction from the check sequence for functions with tiny frames, +the stack is allowed to protrude StackSmall bytes below the stack +guard. Functions with large frames don't bother with the check and +always call morestack. The sequences are (for amd64, others are +similar): + + guard = g->stackguard + frame = function's stack frame size + argsize = size of function arguments (call + return) + + stack frame size <= StackSmall: + CMPQ guard, SP + JHI 3(PC) + MOVQ m->morearg, $(argsize << 32) + CALL morestack(SB) + + stack frame size > StackSmall but < StackBig + LEAQ (frame-StackSmall)(SP), R0 + CMPQ guard, R0 + JHI 3(PC) + MOVQ m->morearg, $(argsize << 32) + CALL morestack(SB) + + stack frame size >= StackBig: + MOVQ m->morearg, $((argsize << 32) | frame) + CALL morestack(SB) + +The bottom StackGuard - StackSmall bytes are important: there has +to be enough room to execute functions that refuse to check for +stack overflow, either because they need to be adjacent to the +actual caller's frame (deferproc) or because they handle the imminent +stack overflow (morestack). + +For example, deferproc might call malloc, which does one of the +above checks (without allocating a full frame), which might trigger +a call to morestack. This sequence needs to fit in the bottom +section of the stack. On amd64, morestack's frame is 40 bytes, and +deferproc's frame is 56 bytes. That fits well within the +StackGuard - StackSmall = 128 bytes at the bottom. +The linkers explore all possible call traces involving non-splitting +functions to make sure that this limit cannot be violated. + */ + +enum { + // The amount of extra stack to allocate beyond the size + // needed for the single frame that triggered the split. + StackExtra = 1024, + + // The minimum stack segment size to allocate. + // If the amount needed for the splitting frame + StackExtra + // is less than this number, the stack will have this size instead. + StackMin = 4096, + + // Functions that need frames bigger than this call morestack + // unconditionally. That is, on entry to a function it is assumed + // that the amount of space available in the current stack segment + // couldn't possibly be bigger than StackBig. If stack segments + // do run with more space than StackBig, the space may not be + // used efficiently. As a result, StackBig should not be significantly + // smaller than StackMin or StackExtra. + StackBig = 4096, + + // The stack guard is a pointer this many bytes above the + // bottom of the stack. + StackGuard = 256, + + // After a stack split check the SP is allowed to be this + // many bytes below the stack guard. This saves an instruction + // in the checking sequence for tiny frames. + StackSmall = 128, + + // The maximum number of bytes that a chain of NOSPLIT + // functions can use. + StackLimit = StackGuard - StackSmall, +}; diff --git a/src/pkg/runtime/type.go b/src/pkg/runtime/type.go index 87268db4c..71ad4e7a5 100644 --- a/src/pkg/runtime/type.go +++ b/src/pkg/runtime/type.go @@ -9,7 +9,7 @@ * data structures and must be kept in sync with this file: * * ../../cmd/gc/reflect.c - * ../../cmd/ld/dwarf.c + * ../../cmd/ld/dwarf.c decodetype_* * ../reflect/type.go * type.h */ @@ -35,6 +35,7 @@ type commonType struct { kind uint8 // enumeration for C string *string // string form; unnecessary but undeniably useful *uncommonType // (relatively) uncommon fields + ptrToThis *Type // pointer to this type, if used in binary or has methods } // Values for commonType.kind. diff --git a/src/pkg/runtime/type.h b/src/pkg/runtime/type.h index c7d9dace2..1adb6dc2e 100644 --- a/src/pkg/runtime/type.h +++ b/src/pkg/runtime/type.h @@ -31,6 +31,7 @@ struct CommonType uint8 kind; String *string; UncommonType *x; + Type *ptrto; }; enum { diff --git a/src/pkg/runtime/windows/386/signal.c b/src/pkg/runtime/windows/386/signal.c index 903636910..08b32a137 100644 --- a/src/pkg/runtime/windows/386/signal.c +++ b/src/pkg/runtime/windows/386/signal.c @@ -85,7 +85,6 @@ runtime·sighandler(ExceptionRecord *info, void *frame, Context *r) runtime·dumpregs(r); } - runtime·breakpoint(); runtime·exit(2); return 0; } diff --git a/src/pkg/runtime/windows/signals.h b/src/pkg/runtime/windows/signals.h new file mode 100644 index 000000000..6943714b0 --- /dev/null +++ b/src/pkg/runtime/windows/signals.h @@ -0,0 +1,3 @@ +// 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. |