summaryrefslogtreecommitdiff
path: root/src/pkg/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime')
-rw-r--r--src/pkg/runtime/Makefile12
-rw-r--r--src/pkg/runtime/amd64/asm.s20
-rw-r--r--src/pkg/runtime/amd64/traceback.c23
-rw-r--r--src/pkg/runtime/arm/asm.s41
-rw-r--r--src/pkg/runtime/arm/cas5.s43
-rw-r--r--src/pkg/runtime/arm/cas6.s29
-rw-r--r--src/pkg/runtime/arm/traceback.c37
-rw-r--r--src/pkg/runtime/cgocall.c3
-rw-r--r--src/pkg/runtime/chan.c47
-rw-r--r--src/pkg/runtime/darwin/386/signal.c10
-rw-r--r--src/pkg/runtime/darwin/386/sys.s29
-rw-r--r--src/pkg/runtime/darwin/amd64/signal.c10
-rw-r--r--src/pkg/runtime/darwin/amd64/sys.s19
-rw-r--r--src/pkg/runtime/darwin/thread.c3
-rw-r--r--src/pkg/runtime/freebsd/386/signal.c10
-rw-r--r--src/pkg/runtime/freebsd/386/sys.s42
-rw-r--r--src/pkg/runtime/freebsd/amd64/signal.c10
-rw-r--r--src/pkg/runtime/freebsd/amd64/sys.s24
-rw-r--r--src/pkg/runtime/freebsd/thread.c3
-rw-r--r--src/pkg/runtime/hashmap.c18
-rw-r--r--src/pkg/runtime/iface.c33
-rw-r--r--src/pkg/runtime/linux/386/signal.c10
-rw-r--r--src/pkg/runtime/linux/386/sys.s7
-rw-r--r--src/pkg/runtime/linux/amd64/signal.c10
-rw-r--r--src/pkg/runtime/linux/amd64/sys.s10
-rw-r--r--src/pkg/runtime/linux/arm/signal.c9
-rw-r--r--src/pkg/runtime/linux/arm/sys.s31
-rw-r--r--src/pkg/runtime/linux/thread.c3
-rw-r--r--src/pkg/runtime/malloc.goc17
-rw-r--r--src/pkg/runtime/mfinal.c5
-rw-r--r--src/pkg/runtime/mgc0.c61
-rw-r--r--src/pkg/runtime/print.c59
-rw-r--r--src/pkg/runtime/proc.c114
-rw-r--r--src/pkg/runtime/runtime-gdb.py5
-rw-r--r--src/pkg/runtime/runtime.c40
-rw-r--r--src/pkg/runtime/runtime.h92
-rw-r--r--src/pkg/runtime/stack.h86
-rw-r--r--src/pkg/runtime/type.go3
-rw-r--r--src/pkg/runtime/type.h1
-rw-r--r--src/pkg/runtime/windows/386/signal.c1
-rw-r--r--src/pkg/runtime/windows/signals.h3
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.