summaryrefslogtreecommitdiff
path: root/src/pkg/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime')
-rw-r--r--src/pkg/runtime/386/asm.s2
-rw-r--r--src/pkg/runtime/Makefile1
-rw-r--r--src/pkg/runtime/amd64/asm.s2
-rw-r--r--src/pkg/runtime/arm/asm.s2
-rw-r--r--src/pkg/runtime/arm/softfloat.c20
-rw-r--r--src/pkg/runtime/chan.c111
-rw-r--r--src/pkg/runtime/darwin/386/signal.c7
-rw-r--r--src/pkg/runtime/darwin/386/sys.s10
-rw-r--r--src/pkg/runtime/darwin/amd64/signal.c7
-rw-r--r--src/pkg/runtime/darwin/amd64/sys.s9
-rw-r--r--src/pkg/runtime/darwin/mem.c7
-rw-r--r--src/pkg/runtime/darwin/os.h2
-rw-r--r--src/pkg/runtime/debug/stack.go4
-rw-r--r--src/pkg/runtime/extern.go2
-rw-r--r--src/pkg/runtime/freebsd/386/signal.c7
-rw-r--r--src/pkg/runtime/freebsd/386/sys.s14
-rw-r--r--src/pkg/runtime/freebsd/amd64/signal.c7
-rw-r--r--src/pkg/runtime/freebsd/amd64/sys.s12
-rw-r--r--src/pkg/runtime/freebsd/mem.c9
-rw-r--r--src/pkg/runtime/freebsd/os.h2
-rw-r--r--src/pkg/runtime/hashmap.c121
-rw-r--r--src/pkg/runtime/iface.c59
-rw-r--r--src/pkg/runtime/linux/386/signal.c7
-rw-r--r--src/pkg/runtime/linux/386/sys.s8
-rw-r--r--src/pkg/runtime/linux/amd64/signal.c7
-rw-r--r--src/pkg/runtime/linux/amd64/sys.s9
-rw-r--r--src/pkg/runtime/linux/arm/signal.c7
-rw-r--r--src/pkg/runtime/linux/arm/sys.s12
-rw-r--r--src/pkg/runtime/linux/mem.c7
-rw-r--r--src/pkg/runtime/linux/os.h2
-rw-r--r--src/pkg/runtime/malloc.goc2
-rw-r--r--src/pkg/runtime/mcache.c2
-rw-r--r--src/pkg/runtime/mgc0.c40
-rw-r--r--src/pkg/runtime/mheap.c8
-rw-r--r--src/pkg/runtime/mkversion.c2
-rw-r--r--src/pkg/runtime/plan9/mem.c2
-rw-r--r--src/pkg/runtime/plan9/thread.c5
-rw-r--r--src/pkg/runtime/proc.c44
-rw-r--r--src/pkg/runtime/proc_test.go43
-rw-r--r--src/pkg/runtime/reflect.goc114
-rw-r--r--src/pkg/runtime/runtime-gdb.py11
-rw-r--r--src/pkg/runtime/runtime.h6
-rw-r--r--src/pkg/runtime/symtab.c4
-rw-r--r--src/pkg/runtime/type.go5
-rw-r--r--src/pkg/runtime/windows/thread.c6
45 files changed, 597 insertions, 173 deletions
diff --git a/src/pkg/runtime/386/asm.s b/src/pkg/runtime/386/asm.s
index 598fc6846..e2cabef14 100644
--- a/src/pkg/runtime/386/asm.s
+++ b/src/pkg/runtime/386/asm.s
@@ -149,7 +149,7 @@ TEXT runtime·gogocall(SB), 7, $0
// void mcall(void (*fn)(G*))
// Switch to m->g0's stack, call fn(g).
-// Fn must never return. It should gogo(&g->gobuf)
+// Fn must never return. It should gogo(&g->sched)
// to keep running g.
TEXT runtime·mcall(SB), 7, $0
MOVL fn+0(FP), DI
diff --git a/src/pkg/runtime/Makefile b/src/pkg/runtime/Makefile
index 4da78c5f0..b122e0599 100644
--- a/src/pkg/runtime/Makefile
+++ b/src/pkg/runtime/Makefile
@@ -71,7 +71,6 @@ OFILES=\
msize.$O\
print.$O\
proc.$O\
- reflect.$O\
rune.$O\
runtime.$O\
runtime1.$O\
diff --git a/src/pkg/runtime/amd64/asm.s b/src/pkg/runtime/amd64/asm.s
index a611985c5..46d82e365 100644
--- a/src/pkg/runtime/amd64/asm.s
+++ b/src/pkg/runtime/amd64/asm.s
@@ -133,7 +133,7 @@ TEXT runtime·gogocall(SB), 7, $0
// void mcall(void (*fn)(G*))
// Switch to m->g0's stack, call fn(g).
-// Fn must never return. It should gogo(&g->gobuf)
+// Fn must never return. It should gogo(&g->sched)
// to keep running g.
TEXT runtime·mcall(SB), 7, $0
MOVQ fn+0(FP), DI
diff --git a/src/pkg/runtime/arm/asm.s b/src/pkg/runtime/arm/asm.s
index 4d36606a7..63153658f 100644
--- a/src/pkg/runtime/arm/asm.s
+++ b/src/pkg/runtime/arm/asm.s
@@ -128,7 +128,7 @@ TEXT runtime·gogocall(SB), 7, $-4
// void mcall(void (*fn)(G*))
// Switch to m->g0's stack, call fn(g).
-// Fn must never return. It should gogo(&g->gobuf)
+// Fn must never return. It should gogo(&g->sched)
// to keep running g.
TEXT runtime·mcall(SB), 7, $-4
MOVW fn+0(FP), R0
diff --git a/src/pkg/runtime/arm/softfloat.c b/src/pkg/runtime/arm/softfloat.c
index f60fab14f..f91a6fc09 100644
--- a/src/pkg/runtime/arm/softfloat.c
+++ b/src/pkg/runtime/arm/softfloat.c
@@ -91,6 +91,7 @@ static uint32
stepflt(uint32 *pc, uint32 *regs)
{
uint32 i, regd, regm, regn;
+ int32 delta;
uint32 *addr;
uint64 uval;
int64 sval;
@@ -117,7 +118,7 @@ stepflt(uint32 *pc, uint32 *regs)
return 1;
}
if(i == 0xe08bb00d) {
- // add sp to 11.
+ // add sp to r11.
// might be part of a large stack offset address
// (or might not, but again no harm done).
regs[11] += regs[13];
@@ -134,6 +135,19 @@ stepflt(uint32 *pc, uint32 *regs)
runtime·printf("*** fpsr R[CPSR] = F[CPSR] %x\n", regs[CPSR]);
return 1;
}
+ if((i&0xff000000) == 0xea000000) {
+ // unconditional branch
+ // can happen in the middle of floating point
+ // if the linker decides it is time to lay down
+ // a sequence of instruction stream constants.
+ delta = i&0xffffff;
+ delta = (delta<<8) >> 8; // sign extend
+
+ if(trace)
+ runtime·printf("*** cpu PC += %x\n", (delta+2)*4);
+ return delta+2;
+ }
+
goto stage1;
stage1: // load/store regn is cpureg, regm is 8bit offset
@@ -489,8 +503,10 @@ runtime·_sfloat2(uint32 *lr, uint32 r0)
uint32 skip;
skip = stepflt(lr, &r0);
- if(skip == 0)
+ if(skip == 0) {
+ runtime·printf("sfloat2 %p %x\n", lr, *lr);
fabort(); // not ok to fail first instruction
+ }
lr += skip;
while(skip = stepflt(lr, &r0))
diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c
index 8c45b076d..f94c3ef40 100644
--- a/src/pkg/runtime/chan.c
+++ b/src/pkg/runtime/chan.c
@@ -9,7 +9,6 @@
static int32 debug = 0;
-typedef struct Link Link;
typedef struct WaitQ WaitQ;
typedef struct SudoG SudoG;
typedef struct Select Select;
@@ -51,12 +50,6 @@ struct Hchan
// chanbuf(c, i) is pointer to the i'th slot in the buffer.
#define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i))
-struct Link
-{
- Link* link; // asynch queue circular linked list
- byte elem[8]; // asynch queue data element (+ more)
-};
-
enum
{
// Scase.kind
@@ -121,7 +114,6 @@ runtime·makechan_c(Type *elem, int64 hint)
by = runtime·mal(n + hint*elem->size);
c = (Hchan*)by;
- by += n;
runtime·addfinalizer(c, destroychan, 0);
c->elemsize = elem->size;
@@ -136,6 +128,15 @@ runtime·makechan_c(Type *elem, int64 hint)
return c;
}
+// For reflect
+// func makechan(typ *ChanType, size uint32) (chan)
+void
+reflect·makechan(ChanType *t, uint32 size, Hchan *c)
+{
+ c = runtime·makechan_c(t->elem, size);
+ FLUSH(&c);
+}
+
static void
destroychan(Hchan *c)
{
@@ -271,6 +272,7 @@ closed:
runtime·panicstring("send on closed channel");
}
+
void
runtime·chanrecv(Hchan* c, byte *ep, bool *selected, bool *received)
{
@@ -527,6 +529,71 @@ runtime·selectnbrecv2(byte *v, bool *received, Hchan *c, bool selected)
runtime·chanrecv(c, v, &selected, received);
}
+// For reflect:
+// func chansend(c chan, val iword, nb bool) (selected bool)
+// where an iword is the same word an interface value would use:
+// the actual data if it fits, or else a pointer to the data.
+//
+// The "uintptr selected" is really "bool selected" but saying
+// uintptr gets us the right alignment for the output parameter block.
+void
+reflect·chansend(Hchan *c, uintptr val, bool nb, uintptr selected)
+{
+ bool *sp;
+ byte *vp;
+
+ if(c == nil)
+ runtime·panicstring("send to nil channel");
+
+ if(nb) {
+ selected = false;
+ sp = (bool*)&selected;
+ } else {
+ *(bool*)&selected = true;
+ FLUSH(&selected);
+ sp = nil;
+ }
+ if(c->elemsize <= sizeof(val))
+ vp = (byte*)&val;
+ else
+ vp = (byte*)val;
+ runtime·chansend(c, vp, sp);
+}
+
+// For reflect:
+// func chanrecv(c chan, nb bool) (val iword, selected, received bool)
+// where an iword is the same word an interface value would use:
+// the actual data if it fits, or else a pointer to the data.
+void
+reflect·chanrecv(Hchan *c, bool nb, uintptr val, bool selected, bool received)
+{
+ byte *vp;
+ bool *sp;
+
+ if(c == nil)
+ runtime·panicstring("receive from nil channel");
+
+ if(nb) {
+ selected = false;
+ sp = &selected;
+ } else {
+ selected = true;
+ FLUSH(&selected);
+ sp = nil;
+ }
+ received = false;
+ FLUSH(&received);
+ if(c->elemsize <= sizeof(val)) {
+ val = 0;
+ vp = (byte*)&val;
+ } else {
+ vp = runtime·mal(c->elemsize);
+ val = (uintptr)vp;
+ FLUSH(&val);
+ }
+ runtime·chanrecv(c, vp, sp, &received);
+}
+
static void newselect(int32, Select**);
// newselect(size uint32) (sel *byte);
@@ -1044,22 +1111,36 @@ runtime·closechan(Hchan *c)
runtime·unlock(c);
}
+// For reflect
+// func chanclose(c chan)
void
-runtime·chanclose(Hchan *c)
+reflect·chanclose(Hchan *c)
{
runtime·closechan(c);
}
-int32
-runtime·chanlen(Hchan *c)
+// For reflect
+// func chanlen(c chan) (len int32)
+void
+reflect·chanlen(Hchan *c, int32 len)
{
- return c->qcount;
+ if(c == nil)
+ len = 0;
+ else
+ len = c->qcount;
+ FLUSH(&len);
}
-int32
-runtime·chancap(Hchan *c)
+// For reflect
+// func chancap(c chan) (cap int32)
+void
+reflect·chancap(Hchan *c, int32 cap)
{
- return c->dataqsiz;
+ if(c == nil)
+ cap = 0;
+ else
+ cap = c->dataqsiz;
+ FLUSH(&cap);
}
static SudoG*
diff --git a/src/pkg/runtime/darwin/386/signal.c b/src/pkg/runtime/darwin/386/signal.c
index 35bbb178b..29170b669 100644
--- a/src/pkg/runtime/darwin/386/signal.c
+++ b/src/pkg/runtime/darwin/386/signal.c
@@ -185,3 +185,10 @@ runtime·resetcpuprofiler(int32 hz)
}
m->profilehz = hz;
}
+
+void
+os·sigpipe(void)
+{
+ sigaction(SIGPIPE, SIG_DFL, false);
+ runtime·raisesigpipe();
+}
diff --git a/src/pkg/runtime/darwin/386/sys.s b/src/pkg/runtime/darwin/386/sys.s
index 08eca9d5a..87fbdbb79 100644
--- a/src/pkg/runtime/darwin/386/sys.s
+++ b/src/pkg/runtime/darwin/386/sys.s
@@ -33,6 +33,16 @@ TEXT runtime·write(SB),7,$0
INT $0x80
RET
+TEXT runtime·raisesigpipe(SB),7,$8
+ get_tls(CX)
+ MOVL m(CX), DX
+ MOVL m_procid(DX), DX
+ MOVL DX, 0(SP) // thread_port
+ MOVL $13, 4(SP) // signal: SIGPIPE
+ MOVL $328, AX // __pthread_kill
+ INT $0x80
+ RET
+
TEXT runtime·mmap(SB),7,$0
MOVL $197, AX
INT $0x80
diff --git a/src/pkg/runtime/darwin/amd64/signal.c b/src/pkg/runtime/darwin/amd64/signal.c
index 3a99d2308..036a3aca7 100644
--- a/src/pkg/runtime/darwin/amd64/signal.c
+++ b/src/pkg/runtime/darwin/amd64/signal.c
@@ -195,3 +195,10 @@ runtime·resetcpuprofiler(int32 hz)
}
m->profilehz = hz;
}
+
+void
+os·sigpipe(void)
+{
+ sigaction(SIGPIPE, SIG_DFL, false);
+ runtime·raisesigpipe();
+}
diff --git a/src/pkg/runtime/darwin/amd64/sys.s b/src/pkg/runtime/darwin/amd64/sys.s
index 39398e065..8d1b20f11 100644
--- a/src/pkg/runtime/darwin/amd64/sys.s
+++ b/src/pkg/runtime/darwin/amd64/sys.s
@@ -38,6 +38,15 @@ TEXT runtime·write(SB),7,$0
SYSCALL
RET
+TEXT runtime·raisesigpipe(SB),7,$24
+ get_tls(CX)
+ MOVQ m(CX), DX
+ MOVL $13, DI // arg 1 SIGPIPE
+ MOVQ m_procid(DX), SI // arg 2 thread_port
+ MOVL $(0x2000000+328), AX // syscall entry __pthread_kill
+ SYSCALL
+ RET
+
TEXT runtime·setitimer(SB), 7, $0
MOVL 8(SP), DI
MOVQ 16(SP), SI
diff --git a/src/pkg/runtime/darwin/mem.c b/src/pkg/runtime/darwin/mem.c
index cbae18718..935c032bc 100644
--- a/src/pkg/runtime/darwin/mem.c
+++ b/src/pkg/runtime/darwin/mem.c
@@ -36,6 +36,11 @@ runtime·SysReserve(void *v, uintptr n)
return runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
}
+enum
+{
+ ENOMEM = 12,
+};
+
void
runtime·SysMap(void *v, uintptr n)
{
@@ -43,6 +48,8 @@ runtime·SysMap(void *v, uintptr n)
mstats.sys += n;
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+ if(p == (void*)-ENOMEM)
+ runtime·throw("runtime: out of memory");
if(p != v)
runtime·throw("runtime: cannot map pages in arena address space");
}
diff --git a/src/pkg/runtime/darwin/os.h b/src/pkg/runtime/darwin/os.h
index 339768e51..db3c2e8a7 100644
--- a/src/pkg/runtime/darwin/os.h
+++ b/src/pkg/runtime/darwin/os.h
@@ -27,3 +27,5 @@ void runtime·sigaltstack(struct StackT*, struct StackT*);
void runtime·sigtramp(void);
void runtime·sigpanic(void);
void runtime·setitimer(int32, Itimerval*, Itimerval*);
+
+void runtime·raisesigpipe(void);
diff --git a/src/pkg/runtime/debug/stack.go b/src/pkg/runtime/debug/stack.go
index e7d56ac23..e5fae632b 100644
--- a/src/pkg/runtime/debug/stack.go
+++ b/src/pkg/runtime/debug/stack.go
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// The debug package contains facilities for programs to debug themselves
-// while they are running.
+// Package debug contains facilities for programs to debug themselves while
+// they are running.
package debug
import (
diff --git a/src/pkg/runtime/extern.go b/src/pkg/runtime/extern.go
index c6e664abb..9da3423c6 100644
--- a/src/pkg/runtime/extern.go
+++ b/src/pkg/runtime/extern.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
/*
- The runtime package contains operations that interact with Go's runtime system,
+ Package runtime contains operations that interact with Go's runtime system,
such as functions to control goroutines. It also includes the low-level type information
used by the reflect package; see reflect's documentation for the programmable
interface to the run-time type system.
diff --git a/src/pkg/runtime/freebsd/386/signal.c b/src/pkg/runtime/freebsd/386/signal.c
index 1ae2554eb..3600f0762 100644
--- a/src/pkg/runtime/freebsd/386/signal.c
+++ b/src/pkg/runtime/freebsd/386/signal.c
@@ -182,3 +182,10 @@ runtime·resetcpuprofiler(int32 hz)
}
m->profilehz = hz;
}
+
+void
+os·sigpipe(void)
+{
+ sigaction(SIGPIPE, SIG_DFL, false);
+ runtime·raisesigpipe();
+}
diff --git a/src/pkg/runtime/freebsd/386/sys.s b/src/pkg/runtime/freebsd/386/sys.s
index c4715b668..765e2fcc4 100644
--- a/src/pkg/runtime/freebsd/386/sys.s
+++ b/src/pkg/runtime/freebsd/386/sys.s
@@ -60,6 +60,20 @@ TEXT runtime·write(SB),7,$-4
INT $0x80
RET
+TEXT runtime·raisesigpipe(SB),7,$12
+ // thr_self(&8(SP))
+ LEAL 8(SP), AX
+ MOVL AX, 0(SP)
+ MOVL $432, AX
+ INT $0x80
+ // thr_kill(self, SIGPIPE)
+ MOVL 8(SP), AX
+ MOVL AX, 0(SP)
+ MOVL $13, 4(SP)
+ MOVL $433, AX
+ INT $0x80
+ RET
+
TEXT runtime·notok(SB),7,$0
MOVL $0xf1, 0xf1
RET
diff --git a/src/pkg/runtime/freebsd/amd64/signal.c b/src/pkg/runtime/freebsd/amd64/signal.c
index 9d8e5e692..85cb1d855 100644
--- a/src/pkg/runtime/freebsd/amd64/signal.c
+++ b/src/pkg/runtime/freebsd/amd64/signal.c
@@ -190,3 +190,10 @@ runtime·resetcpuprofiler(int32 hz)
}
m->profilehz = hz;
}
+
+void
+os·sigpipe(void)
+{
+ sigaction(SIGPIPE, SIG_DFL, false);
+ runtime·raisesigpipe();
+}
diff --git a/src/pkg/runtime/freebsd/amd64/sys.s b/src/pkg/runtime/freebsd/amd64/sys.s
index 9a6fdf1ac..c5cc082e4 100644
--- a/src/pkg/runtime/freebsd/amd64/sys.s
+++ b/src/pkg/runtime/freebsd/amd64/sys.s
@@ -65,6 +65,18 @@ TEXT runtime·write(SB),7,$-8
SYSCALL
RET
+TEXT runtime·raisesigpipe(SB),7,$16
+ // thr_self(&8(SP))
+ LEAQ 8(SP), DI // arg 1 &8(SP)
+ MOVL $432, AX
+ SYSCALL
+ // thr_kill(self, SIGPIPE)
+ MOVQ 8(SP), DI // arg 1 id
+ MOVQ $13, SI // arg 2 SIGPIPE
+ MOVL $433, AX
+ SYSCALL
+ RET
+
TEXT runtime·setitimer(SB), 7, $-8
MOVL 8(SP), DI
MOVQ 16(SP), SI
diff --git a/src/pkg/runtime/freebsd/mem.c b/src/pkg/runtime/freebsd/mem.c
index f80439e38..07abf2cfe 100644
--- a/src/pkg/runtime/freebsd/mem.c
+++ b/src/pkg/runtime/freebsd/mem.c
@@ -42,6 +42,11 @@ runtime·SysReserve(void *v, uintptr n)
return runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
}
+enum
+{
+ ENOMEM = 12,
+};
+
void
runtime·SysMap(void *v, uintptr n)
{
@@ -52,6 +57,8 @@ runtime·SysMap(void *v, uintptr n)
// On 64-bit, we don't actually have v reserved, so tread carefully.
if(sizeof(void*) == 8) {
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p == (void*)-ENOMEM)
+ runtime·throw("runtime: out of memory");
if(p != v) {
runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
runtime·throw("runtime: address space conflict");
@@ -60,6 +67,8 @@ runtime·SysMap(void *v, uintptr n)
}
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+ if(p == (void*)-ENOMEM)
+ runtime·throw("runtime: out of memory");
if(p != v)
runtime·throw("runtime: cannot map pages in arena address space");
}
diff --git a/src/pkg/runtime/freebsd/os.h b/src/pkg/runtime/freebsd/os.h
index 13754688b..007856c6b 100644
--- a/src/pkg/runtime/freebsd/os.h
+++ b/src/pkg/runtime/freebsd/os.h
@@ -8,3 +8,5 @@ struct sigaction;
void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
void runtiem·setitimerval(int32, Itimerval*, Itimerval*);
void runtime·setitimer(int32, Itimerval*, Itimerval*);
+
+void runtime·raisesigpipe(void);
diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.c
index e50cefd9a..5ba1eb20a 100644
--- a/src/pkg/runtime/hashmap.c
+++ b/src/pkg/runtime/hashmap.c
@@ -776,6 +776,15 @@ runtime·makemap(Type *key, Type *val, int64 hint, Hmap *ret)
FLUSH(&ret);
}
+// For reflect:
+// func makemap(Type *mapType) (hmap *map)
+void
+reflect·makemap(MapType *t, Hmap *ret)
+{
+ ret = runtime·makemap_c(t->key, t->elem, 0);
+ FLUSH(&ret);
+}
+
void
runtime·mapaccess(Hmap *h, byte *ak, byte *av, bool *pres)
{
@@ -855,6 +864,34 @@ runtime·mapaccess2(Hmap *h, ...)
}
}
+// For reflect:
+// func mapaccess(h map, key iword) (val iword, pres bool)
+// where an iword is the same word an interface value would use:
+// the actual data if it fits, or else a pointer to the data.
+void
+reflect·mapaccess(Hmap *h, uintptr key, uintptr val, bool pres)
+{
+ byte *ak, *av;
+
+ if(h == nil)
+ runtime·panicstring("lookup in nil map");
+ if(h->keysize <= sizeof(key))
+ ak = (byte*)&key;
+ else
+ ak = (byte*)key;
+ val = 0;
+ pres = false;
+ if(h->valsize <= sizeof(val))
+ av = (byte*)&val;
+ else {
+ av = runtime·mal(h->valsize);
+ val = (uintptr)av;
+ }
+ runtime·mapaccess(h, ak, av, &pres);
+ FLUSH(&val);
+ FLUSH(&pres);
+}
+
void
runtime·mapassign(Hmap *h, byte *ak, byte *av)
{
@@ -938,6 +975,30 @@ runtime·mapassign2(Hmap *h, ...)
}
}
+// For reflect:
+// func mapassign(h map, key, val iword, pres bool)
+// where an iword is the same word an interface value would use:
+// the actual data if it fits, or else a pointer to the data.
+void
+reflect·mapassign(Hmap *h, uintptr key, uintptr val, bool pres)
+{
+ byte *ak, *av;
+
+ if(h == nil)
+ runtime·panicstring("lookup in nil map");
+ if(h->keysize <= sizeof(key))
+ ak = (byte*)&key;
+ else
+ ak = (byte*)key;
+ if(h->valsize <= sizeof(val))
+ av = (byte*)&val;
+ else
+ av = (byte*)val;
+ if(!pres)
+ av = nil;
+ runtime·mapassign(h, ak, av);
+}
+
// mapiterinit(hmap *map[any]any, hiter *any);
void
runtime·mapiterinit(Hmap *h, struct hash_iter *it)
@@ -959,14 +1020,14 @@ runtime·mapiterinit(Hmap *h, struct hash_iter *it)
}
}
-struct hash_iter*
-runtime·newmapiterinit(Hmap *h)
+// For reflect:
+// func mapiterinit(h map) (it iter)
+void
+reflect·mapiterinit(Hmap *h, struct hash_iter *it)
{
- struct hash_iter *it;
-
it = runtime·mal(sizeof *it);
+ FLUSH(&it);
runtime·mapiterinit(h, it);
- return it;
}
// mapiternext(hiter *any);
@@ -986,6 +1047,14 @@ runtime·mapiternext(struct hash_iter *it)
}
}
+// For reflect:
+// func mapiternext(it iter)
+void
+reflect·mapiternext(struct hash_iter *it)
+{
+ runtime·mapiternext(it);
+}
+
// mapiter1(hiter *any) (key any);
#pragma textflag 7
void
@@ -1026,6 +1095,48 @@ runtime·mapiterkey(struct hash_iter *it, void *ak)
return true;
}
+// For reflect:
+// func mapiterkey(h map) (key iword, ok bool)
+// where an iword is the same word an interface value would use:
+// the actual data if it fits, or else a pointer to the data.
+void
+reflect·mapiterkey(struct hash_iter *it, uintptr key, bool ok)
+{
+ Hmap *h;
+ byte *res;
+
+ key = 0;
+ ok = false;
+ h = it->h;
+ res = it->data;
+ if(res == nil) {
+ key = 0;
+ ok = false;
+ } else {
+ key = 0;
+ if(h->keysize <= sizeof(key))
+ h->keyalg->copy(h->keysize, (byte*)&key, res);
+ else
+ key = (uintptr)res;
+ ok = true;
+ }
+ FLUSH(&key);
+ FLUSH(&ok);
+}
+
+// For reflect:
+// func maplen(h map) (len int32)
+// Like len(m) in the actual language, we treat the nil map as length 0.
+void
+reflect·maplen(Hmap *h, int32 len)
+{
+ if(h == nil)
+ len = 0;
+ else
+ len = h->count;
+ FLUSH(&len);
+}
+
// mapiter2(hiter *any) (key any, val any);
#pragma textflag 7
void
diff --git a/src/pkg/runtime/iface.c b/src/pkg/runtime/iface.c
index 698aead3d..b1015f695 100644
--- a/src/pkg/runtime/iface.c
+++ b/src/pkg/runtime/iface.c
@@ -6,6 +6,14 @@
#include "type.h"
#include "malloc.h"
+enum
+{
+ // If an empty interface has these bits set in its type
+ // pointer, it was copied from a reflect.Value and is
+ // not a valid empty interface.
+ reflectFlags = 3,
+};
+
void
runtime·printiface(Iface i)
{
@@ -42,7 +50,7 @@ itab(InterfaceType *inter, Type *type, int32 canfail)
Method *t, *et;
IMethod *i, *ei;
uint32 h;
- String *iname;
+ String *iname, *ipkgPath;
Itab *m;
UncommonType *x;
Type *itype;
@@ -112,6 +120,7 @@ search:
for(; i < ei; i++) {
itype = i->type;
iname = i->name;
+ ipkgPath = i->pkgPath;
for(;; t++) {
if(t >= et) {
if(!canfail) {
@@ -128,7 +137,7 @@ search:
m->bad = 1;
goto out;
}
- if(t->mtyp == itype && t->name == iname)
+ if(t->mtyp == itype && t->name == iname && t->pkgPath == ipkgPath)
break;
}
if(m)
@@ -276,6 +285,8 @@ runtime·assertE2T(Type *t, Eface e, ...)
{
byte *ret;
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
ret = (byte*)(&e+1);
assertE2Tret(t, e, ret);
}
@@ -285,6 +296,8 @@ assertE2Tret(Type *t, Eface e, byte *ret)
{
Eface err;
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
if(e.type == nil) {
runtime·newTypeAssertionError(nil, nil, t,
nil, nil, t->string,
@@ -309,6 +322,8 @@ runtime·assertE2T2(Type *t, Eface e, ...)
bool *ok;
int32 wid;
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
ret = (byte*)(&e+1);
wid = t->size;
ok = (bool*)(ret+runtime·rnd(wid, 1));
@@ -444,6 +459,8 @@ runtime·ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
Type *t;
Eface err;
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
t = e.type;
if(t == nil) {
// explicit conversions require non-nil interface value.
@@ -456,6 +473,14 @@ runtime·ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
ret->tab = itab(inter, t, 0);
}
+// For reflect
+// func ifaceE2I(t *InterfaceType, e interface{}, dst *Iface)
+void
+reflect·ifaceE2I(InterfaceType *inter, Eface e, Iface *dst)
+{
+ runtime·ifaceE2I(inter, e, dst);
+}
+
// func ifaceE2I(sigi *byte, iface any) (ret any)
void
runtime·assertE2I(InterfaceType* inter, Eface e, Iface ret)
@@ -467,6 +492,8 @@ runtime·assertE2I(InterfaceType* inter, Eface e, Iface ret)
void
runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
{
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
if(e.type == nil) {
ok = 0;
ret.data = nil;
@@ -489,6 +516,8 @@ runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
Type *t;
Eface err;
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
t = e.type;
if(t == nil) {
// explicit conversions require non-nil interface value.
@@ -505,6 +534,8 @@ runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
void
runtime·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
{
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
USED(inter);
ret = e;
ok = e.type != nil;
@@ -582,6 +613,10 @@ runtime·ifaceeq_c(Iface i1, Iface i2)
bool
runtime·efaceeq_c(Eface e1, Eface e2)
{
+ if(((uintptr)e1.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+ if(((uintptr)e2.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
if(e1.type != e2.type)
return false;
if(e1.type == nil)
@@ -624,6 +659,8 @@ runtime·efacethash(Eface e1, uint32 ret)
{
Type *t;
+ if(((uintptr)e1.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
ret = 0;
t = e1.type;
if(t != nil)
@@ -634,11 +671,14 @@ runtime·efacethash(Eface e1, uint32 ret)
void
unsafe·Typeof(Eface e, Eface ret)
{
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
if(e.type == nil) {
ret.type = nil;
ret.data = nil;
- } else
- ret = *(Eface*)e.type;
+ } else {
+ ret = *(Eface*)(e.type);
+ }
FLUSH(&ret);
}
@@ -648,6 +688,8 @@ unsafe·Reflect(Eface e, Eface rettype, void *retaddr)
uintptr *p;
uintptr x;
+ if(((uintptr)e.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
if(e.type == nil) {
rettype.type = nil;
rettype.data = nil;
@@ -678,6 +720,9 @@ unsafe·Reflect(Eface e, Eface rettype, void *retaddr)
void
unsafe·Unreflect(Eface typ, void *addr, Eface e)
{
+ if(((uintptr)typ.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+
// Reflect library has reinterpreted typ
// as its own kind of type structure.
// We know that the pointer to the original
@@ -702,6 +747,9 @@ unsafe·New(Eface typ, void *ret)
{
Type *t;
+ if(((uintptr)typ.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+
// Reflect library has reinterpreted typ
// as its own kind of type structure.
// We know that the pointer to the original
@@ -721,6 +769,9 @@ unsafe·NewArray(Eface typ, uint32 n, void *ret)
uint64 size;
Type *t;
+ if(((uintptr)typ.type&reflectFlags) != 0)
+ runtime·throw("invalid interface value");
+
// Reflect library has reinterpreted typ
// as its own kind of type structure.
// We know that the pointer to the original
diff --git a/src/pkg/runtime/linux/386/signal.c b/src/pkg/runtime/linux/386/signal.c
index 9b72ecbae..8916e10bd 100644
--- a/src/pkg/runtime/linux/386/signal.c
+++ b/src/pkg/runtime/linux/386/signal.c
@@ -175,3 +175,10 @@ runtime·resetcpuprofiler(int32 hz)
}
m->profilehz = hz;
}
+
+void
+os·sigpipe(void)
+{
+ sigaction(SIGPIPE, SIG_DFL, false);
+ runtime·raisesigpipe();
+}
diff --git a/src/pkg/runtime/linux/386/sys.s b/src/pkg/runtime/linux/386/sys.s
index c39ce253f..868a0d901 100644
--- a/src/pkg/runtime/linux/386/sys.s
+++ b/src/pkg/runtime/linux/386/sys.s
@@ -30,6 +30,14 @@ TEXT runtime·write(SB),7,$0
INT $0x80
RET
+TEXT runtime·raisesigpipe(SB),7,$12
+ MOVL $224, AX // syscall - gettid
+ INT $0x80
+ MOVL AX, 0(SP) // arg 1 tid
+ MOVL $13, 4(SP) // arg 2 SIGPIPE
+ MOVL $238, AX // syscall - tkill
+ INT $0x80
+ RET
TEXT runtime·setitimer(SB),7,$0-24
MOVL $104, AX // syscall - setitimer
diff --git a/src/pkg/runtime/linux/amd64/signal.c b/src/pkg/runtime/linux/amd64/signal.c
index 1db9c95e5..ee90271ed 100644
--- a/src/pkg/runtime/linux/amd64/signal.c
+++ b/src/pkg/runtime/linux/amd64/signal.c
@@ -185,3 +185,10 @@ runtime·resetcpuprofiler(int32 hz)
}
m->profilehz = hz;
}
+
+void
+os·sigpipe(void)
+{
+ sigaction(SIGPIPE, SIG_DFL, false);
+ runtime·raisesigpipe();
+}
diff --git a/src/pkg/runtime/linux/amd64/sys.s b/src/pkg/runtime/linux/amd64/sys.s
index 11df1f894..eadd30005 100644
--- a/src/pkg/runtime/linux/amd64/sys.s
+++ b/src/pkg/runtime/linux/amd64/sys.s
@@ -36,6 +36,15 @@ TEXT runtime·write(SB),7,$0-24
SYSCALL
RET
+TEXT runtime·raisesigpipe(SB),7,$12
+ MOVL $186, AX // syscall - gettid
+ SYSCALL
+ MOVL AX, DI // arg 1 tid
+ MOVL $13, SI // arg 2 SIGPIPE
+ MOVL $200, AX // syscall - tkill
+ SYSCALL
+ RET
+
TEXT runtime·setitimer(SB),7,$0-24
MOVL 8(SP), DI
MOVQ 16(SP), SI
diff --git a/src/pkg/runtime/linux/arm/signal.c b/src/pkg/runtime/linux/arm/signal.c
index 05c6b0261..88a84d112 100644
--- a/src/pkg/runtime/linux/arm/signal.c
+++ b/src/pkg/runtime/linux/arm/signal.c
@@ -180,3 +180,10 @@ runtime·resetcpuprofiler(int32 hz)
}
m->profilehz = hz;
}
+
+void
+os·sigpipe(void)
+{
+ sigaction(SIGPIPE, SIG_DFL, false);
+ runtime·raisesigpipe();
+}
diff --git a/src/pkg/runtime/linux/arm/sys.s b/src/pkg/runtime/linux/arm/sys.s
index b9767a028..d866b0e22 100644
--- a/src/pkg/runtime/linux/arm/sys.s
+++ b/src/pkg/runtime/linux/arm/sys.s
@@ -22,11 +22,12 @@
#define SYS_rt_sigaction (SYS_BASE + 174)
#define SYS_sigaltstack (SYS_BASE + 186)
#define SYS_mmap2 (SYS_BASE + 192)
-#define SYS_gettid (SYS_BASE + 224)
#define SYS_futex (SYS_BASE + 240)
#define SYS_exit_group (SYS_BASE + 248)
#define SYS_munmap (SYS_BASE + 91)
#define SYS_setitimer (SYS_BASE + 104)
+#define SYS_gettid (SYS_BASE + 224)
+#define SYS_tkill (SYS_BASE + 238)
#define ARM_BASE (SYS_BASE + 0x0f0000)
#define SYS_ARM_cacheflush (ARM_BASE + 2)
@@ -55,6 +56,15 @@ TEXT runtime·exit1(SB),7,$-4
MOVW $1003, R1
MOVW R0, (R1) // fail hard
+TEXT runtime·raisesigpipe(SB),7,$-4
+ MOVW $SYS_gettid, R7
+ SWI $0
+ // arg 1 tid already in R0 from gettid
+ MOVW $13, R1 // arg 2 SIGPIPE
+ MOVW $SYS_tkill, R7
+ SWI $0
+ RET
+
TEXT runtime·mmap(SB),7,$0
MOVW 0(FP), R0
MOVW 4(FP), R1
diff --git a/src/pkg/runtime/linux/mem.c b/src/pkg/runtime/linux/mem.c
index d2f6f8204..ce1a8aa70 100644
--- a/src/pkg/runtime/linux/mem.c
+++ b/src/pkg/runtime/linux/mem.c
@@ -48,6 +48,11 @@ runtime·SysReserve(void *v, uintptr n)
return runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
}
+enum
+{
+ ENOMEM = 12,
+};
+
void
runtime·SysMap(void *v, uintptr n)
{
@@ -66,6 +71,8 @@ runtime·SysMap(void *v, uintptr n)
}
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+ if(p == (void*)-ENOMEM)
+ runtime·throw("runtime: out of memory");
if(p != v)
runtime·throw("runtime: cannot map pages in arena address space");
}
diff --git a/src/pkg/runtime/linux/os.h b/src/pkg/runtime/linux/os.h
index 6ae088977..0bb8d0339 100644
--- a/src/pkg/runtime/linux/os.h
+++ b/src/pkg/runtime/linux/os.h
@@ -15,3 +15,5 @@ void runtime·rt_sigaction(uintptr, struct Sigaction*, void*, uintptr);
void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
void runtime·sigpanic(void);
void runtime·setitimer(int32, Itimerval*, Itimerval*);
+
+void runtime·raisesigpipe(void);
diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc
index 41060682e..1f2d6da40 100644
--- a/src/pkg/runtime/malloc.goc
+++ b/src/pkg/runtime/malloc.goc
@@ -346,7 +346,7 @@ runtime·MHeap_SysAlloc(MHeap *h, uintptr n)
return nil;
if(p < h->arena_start || p+n - h->arena_start >= MaxArena32) {
- runtime·printf("runtime: memory allocated by OS not in usable range");
+ runtime·printf("runtime: memory allocated by OS not in usable range\n");
runtime·SysFree(p, n);
return nil;
}
diff --git a/src/pkg/runtime/mcache.c b/src/pkg/runtime/mcache.c
index 0f41a0ebc..e40621186 100644
--- a/src/pkg/runtime/mcache.c
+++ b/src/pkg/runtime/mcache.c
@@ -22,6 +22,8 @@ runtime·MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
// Replenish using central lists.
n = runtime·MCentral_AllocList(&runtime·mheap.central[sizeclass],
runtime·class_to_transfercount[sizeclass], &first);
+ if(n == 0)
+ runtime·throw("out of memory");
l->list = first;
l->nlist = n;
c->size += n*size;
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index 14d485b71..ac6a1fa40 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -6,6 +6,7 @@
#include "runtime.h"
#include "malloc.h"
+#include "stack.h"
enum {
Debug = 0,
@@ -92,6 +93,11 @@ scanblock(byte *b, int64 n)
void **bw, **w, **ew;
Workbuf *wbuf;
+ if((int64)(uintptr)n != n || n < 0) {
+ runtime·printf("scanblock %p %D\n", b, n);
+ runtime·throw("scanblock");
+ }
+
// Memory arena parameters.
arena_start = runtime·mheap.arena_start;
@@ -323,20 +329,46 @@ getfull(Workbuf *b)
static void
scanstack(G *gp)
{
+ int32 n;
Stktop *stk;
- byte *sp;
+ byte *sp, *guard;
+
+ stk = (Stktop*)gp->stackbase;
+ guard = gp->stackguard;
- if(gp == g)
+ if(gp == g) {
+ // Scanning our own stack: start at &gp.
sp = (byte*)&gp;
- else
+ } else {
+ // Scanning another goroutine's stack.
+ // The goroutine is usually asleep (the world is stopped).
sp = gp->sched.sp;
+
+ // The exception is that if the goroutine is about to enter or might
+ // have just exited a system call, it may be executing code such
+ // as schedlock and may have needed to start a new stack segment.
+ // Use the stack segment and stack pointer at the time of
+ // the system call instead, since that won't change underfoot.
+ if(gp->gcstack != nil) {
+ stk = (Stktop*)gp->gcstack;
+ sp = gp->gcsp;
+ guard = gp->gcguard;
+ }
+ }
+
if(Debug > 1)
runtime·printf("scanstack %d %p\n", gp->goid, sp);
- stk = (Stktop*)gp->stackbase;
+ n = 0;
while(stk) {
+ if(sp < guard-StackGuard || (byte*)stk < sp) {
+ runtime·printf("scanstack inconsistent: g%d#%d sp=%p not in [%p,%p]\n", gp->goid, n, sp, guard-StackGuard, stk);
+ runtime·throw("scanstack");
+ }
scanblock(sp, (byte*)stk - sp);
sp = stk->gobuf.sp;
+ guard = stk->stackguard;
stk = (Stktop*)stk->stackbase;
+ n++;
}
}
diff --git a/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c
index 8061b7cf8..dde31ce34 100644
--- a/src/pkg/runtime/mheap.c
+++ b/src/pkg/runtime/mheap.c
@@ -180,9 +180,7 @@ MHeap_Grow(MHeap *h, uintptr npage)
// Allocate a multiple of 64kB (16 pages).
npage = (npage+15)&~15;
ask = npage<<PageShift;
- if(ask > h->arena_end - h->arena_used)
- return false;
- if(ask < HeapAllocChunk && HeapAllocChunk <= h->arena_end - h->arena_used)
+ if(ask < HeapAllocChunk)
ask = HeapAllocChunk;
v = runtime·MHeap_SysAlloc(h, ask);
@@ -191,8 +189,10 @@ MHeap_Grow(MHeap *h, uintptr npage)
ask = npage<<PageShift;
v = runtime·MHeap_SysAlloc(h, ask);
}
- if(v == nil)
+ if(v == nil) {
+ runtime·printf("runtime: out of memory: cannot allocate %D-byte block (%D in use)\n", (uint64)ask, mstats.heap_sys);
return false;
+ }
}
mstats.heap_sys += ask;
diff --git a/src/pkg/runtime/mkversion.c b/src/pkg/runtime/mkversion.c
index 56afa1892..0d96aa356 100644
--- a/src/pkg/runtime/mkversion.c
+++ b/src/pkg/runtime/mkversion.c
@@ -4,7 +4,7 @@
char *template =
"// generated by mkversion.c; do not edit.\n"
"package runtime\n"
- "const defaultGoroot = \"%s\"\n"
+ "const defaultGoroot = `%s`\n"
"const theVersion = \"%s\"\n";
void
diff --git a/src/pkg/runtime/plan9/mem.c b/src/pkg/runtime/plan9/mem.c
index b840de984..9dfdf2cc3 100644
--- a/src/pkg/runtime/plan9/mem.c
+++ b/src/pkg/runtime/plan9/mem.c
@@ -4,6 +4,7 @@
#include "runtime.h"
#include "malloc.h"
+#include "os.h"
extern byte end[];
static byte *bloc = { end };
@@ -52,5 +53,6 @@ runtime·SysMap(void *v, uintptr nbytes)
void*
runtime·SysReserve(void *v, uintptr nbytes)
{
+ USED(v);
return runtime·SysAlloc(nbytes);
}
diff --git a/src/pkg/runtime/plan9/thread.c b/src/pkg/runtime/plan9/thread.c
index fa96552a9..7c6ca45a3 100644
--- a/src/pkg/runtime/plan9/thread.c
+++ b/src/pkg/runtime/plan9/thread.c
@@ -138,3 +138,8 @@ runtime·notewakeup(Note *n)
runtime·usemrelease(&n->sema);
}
+void
+os·sigpipe(void)
+{
+ runtime·throw("too many writes on closed pipe");
+}
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index e212c7820..52784854f 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -590,6 +590,9 @@ schedule(G *gp)
// re-queues g and runs everyone else who is waiting
// before running g again. If g->status is Gmoribund,
// kills off g.
+// Cannot split stack because it is called from exitsyscall.
+// See comment below.
+#pragma textflag 7
void
runtime·gosched(void)
{
@@ -604,19 +607,17 @@ runtime·gosched(void)
// Record that it's not using the cpu anymore.
// This is called only from the go syscall library and cgocall,
// not from the low-level system calls used by the runtime.
+//
// Entersyscall cannot split the stack: the runtime·gosave must
-// make g->sched refer to the caller's stack pointer.
+// make g->sched refer to the caller's stack segment, because
+// entersyscall is going to return immediately after.
// It's okay to call matchmg and notewakeup even after
// decrementing mcpu, because we haven't released the
-// sched lock yet.
+// sched lock yet, so the garbage collector cannot be running.
#pragma textflag 7
void
runtime·entersyscall(void)
{
- // Leave SP around for gc and traceback.
- // Do before notewakeup so that gc
- // never sees Gsyscall with wrong stack.
- runtime·gosave(&g->sched);
if(runtime·sched.predawn)
return;
schedlock();
@@ -625,10 +626,23 @@ runtime·entersyscall(void)
runtime·sched.msyscall++;
if(runtime·sched.gwait != 0)
matchmg();
+
if(runtime·sched.waitstop && runtime·sched.mcpu <= runtime·sched.mcpumax) {
runtime·sched.waitstop = 0;
runtime·notewakeup(&runtime·sched.stopped);
}
+
+ // Leave SP around for gc and traceback.
+ // Do before schedunlock so that gc
+ // never sees Gsyscall with wrong stack.
+ runtime·gosave(&g->sched);
+ g->gcsp = g->sched.sp;
+ g->gcstack = g->stackbase;
+ g->gcguard = g->stackguard;
+ if(g->gcsp < g->gcguard-StackGuard || g->gcstack < g->gcsp) {
+ runtime·printf("entersyscall inconsistent %p [%p,%p]\n", g->gcsp, g->gcguard-StackGuard, g->gcstack);
+ runtime·throw("entersyscall");
+ }
schedunlock();
}
@@ -647,7 +661,11 @@ runtime·exitsyscall(void)
runtime·sched.mcpu++;
// Fast path - if there's room for this m, we're done.
if(m->profilehz == runtime·sched.profilehz && runtime·sched.mcpu <= runtime·sched.mcpumax) {
+ // There's a cpu for us, so we can run.
g->status = Grunning;
+ // Garbage collector isn't running (since we are),
+ // so okay to clear gcstack.
+ g->gcstack = nil;
schedunlock();
return;
}
@@ -663,6 +681,14 @@ runtime·exitsyscall(void)
// When the scheduler takes g away from m,
// it will undo the runtime·sched.mcpu++ above.
runtime·gosched();
+
+ // Gosched returned, so we're allowed to run now.
+ // Delete the gcstack information that we left for
+ // the garbage collector during the system call.
+ // Must wait until now because until gosched returns
+ // we don't know for sure that the garbage collector
+ // is not running.
+ g->gcstack = nil;
}
void
@@ -1196,6 +1222,12 @@ runtime·gomaxprocsfunc(int32 n)
if (n <= 0)
n = ret;
runtime·gomaxprocs = n;
+ if (runtime·gcwaiting != 0) {
+ if (runtime·sched.mcpumax != 1)
+ runtime·throw("invalid runtime·sched.mcpumax during gc");
+ schedunlock();
+ return ret;
+ }
runtime·sched.mcpumax = n;
// handle fewer procs?
if(runtime·sched.mcpu > runtime·sched.mcpumax) {
diff --git a/src/pkg/runtime/proc_test.go b/src/pkg/runtime/proc_test.go
new file mode 100644
index 000000000..a15b2d80a
--- /dev/null
+++ b/src/pkg/runtime/proc_test.go
@@ -0,0 +1,43 @@
+// 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.
+
+package runtime_test
+
+import (
+ "runtime"
+ "testing"
+)
+
+var stop = make(chan bool, 1)
+
+func perpetuumMobile() {
+ select {
+ case <-stop:
+ default:
+ go perpetuumMobile()
+ }
+}
+
+func TestStopTheWorldDeadlock(t *testing.T) {
+ if testing.Short() {
+ t.Logf("skipping during short test")
+ return
+ }
+ runtime.GOMAXPROCS(3)
+ compl := make(chan int, 1)
+ go func() {
+ for i := 0; i != 1000; i += 1 {
+ runtime.GC()
+ }
+ compl <- 0
+ }()
+ go func() {
+ for i := 0; i != 1000; i += 1 {
+ runtime.GOMAXPROCS(3)
+ }
+ }()
+ go perpetuumMobile()
+ <-compl
+ stop <- true
+}
diff --git a/src/pkg/runtime/reflect.goc b/src/pkg/runtime/reflect.goc
deleted file mode 100644
index 9bdc48afb..000000000
--- a/src/pkg/runtime/reflect.goc
+++ /dev/null
@@ -1,114 +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.
-
-package reflect
-#include "runtime.h"
-#include "type.h"
-
-static Type*
-gettype(void *typ)
-{
- // typ is a *runtime.Type (or *runtime.MapType, etc), but the Type
- // defined in type.h includes an interface value header
- // in front of the raw structure. the -2 below backs up
- // to the interface value header.
- return (Type*)((void**)typ - 2);
-}
-
-/*
- * Go wrappers around the C functions near the bottom of hashmap.c
- * There's no recursion here even though it looks like there is:
- * the names after func are in the reflect package name space
- * but the names in the C bodies are in the standard C name space.
- */
-
-func mapaccess(map *byte, key *byte, val *byte) (pres bool) {
- runtime·mapaccess((Hmap*)map, key, val, &pres);
-}
-
-func mapassign(map *byte, key *byte, val *byte) {
- runtime·mapassign((Hmap*)map, key, val);
-}
-
-func maplen(map *byte) (len int32) {
- // length is first word of map
- len = *(uint32*)map;
-}
-
-func mapiterinit(map *byte) (it *byte) {
- it = (byte*)runtime·newmapiterinit((Hmap*)map);
-}
-
-func mapiternext(it *byte) {
- runtime·mapiternext((struct hash_iter*)it);
-}
-
-func mapiterkey(it *byte, key *byte) (ok bool) {
- ok = runtime·mapiterkey((struct hash_iter*)it, key);
-}
-
-func makemap(typ *byte) (map *byte) {
- MapType *t;
-
- t = (MapType*)gettype(typ);
- map = (byte*)runtime·makemap_c(t->key, t->elem, 0);
-}
-
-/*
- * Go wrappers around the C functions in chan.c
- */
-
-func makechan(typ *byte, size uint32) (ch *byte) {
- ChanType *t;
-
- // typ is a *runtime.ChanType, but the ChanType
- // defined in type.h includes an interface value header
- // in front of the raw ChanType. the -2 below backs up
- // to the interface value header.
- t = (ChanType*)gettype(typ);
- ch = (byte*)runtime·makechan_c(t->elem, size);
-}
-
-func chansend(ch *byte, val *byte, selected *bool) {
- runtime·chansend((Hchan*)ch, val, selected);
-}
-
-func chanrecv(ch *byte, val *byte, selected *bool, received *bool) {
- runtime·chanrecv((Hchan*)ch, val, selected, received);
-}
-
-func chanclose(ch *byte) {
- runtime·chanclose((Hchan*)ch);
-}
-
-func chanlen(ch *byte) (r int32) {
- r = runtime·chanlen((Hchan*)ch);
-}
-
-func chancap(ch *byte) (r int32) {
- r = runtime·chancap((Hchan*)ch);
-}
-
-
-/*
- * Go wrappers around the functions in iface.c
- */
-
-func setiface(typ *byte, x *byte, ret *byte) {
- InterfaceType *t;
-
- t = (InterfaceType*)gettype(typ);
- if(t->mhdr.len == 0) {
- // already an empty interface
- *(Eface*)ret = *(Eface*)x;
- return;
- }
- if(((Eface*)x)->type == nil) {
- // can assign nil to any interface
- ((Iface*)ret)->tab = nil;
- ((Iface*)ret)->data = nil;
- return;
- }
- runtime·ifaceE2I((InterfaceType*)gettype(typ), *(Eface*)x, (Iface*)ret);
-}
diff --git a/src/pkg/runtime/runtime-gdb.py b/src/pkg/runtime/runtime-gdb.py
index 08772a431..3f767fbdd 100644
--- a/src/pkg/runtime/runtime-gdb.py
+++ b/src/pkg/runtime/runtime-gdb.py
@@ -122,10 +122,13 @@ class ChanTypePrinter:
return str(self.val.type)
def children(self):
- ptr = self.val['recvdataq']
- for idx in range(self.val["qcount"]):
- yield ('[%d]' % idx, ptr['elem'])
- ptr = ptr['link']
+ # see chan.c chanbuf()
+ et = [x.type for x in self.val['free'].type.target().fields() if x.name == 'elem'][0]
+ ptr = (self.val.address + 1).cast(et.pointer())
+ for i in range(self.val["qcount"]):
+ j = (self.val["recvx"] + i) % self.val["dataqsiz"]
+ yield ('[%d]' % i, (ptr + j).dereference())
+
#
# Register all the *Printer classes above.
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index 6cf2685fd..f9b404e15 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -183,6 +183,9 @@ struct G
Defer* defer;
Panic* panic;
Gobuf sched;
+ byte* gcstack; // if status==Gsyscall, gcstack = stackbase to use during gc
+ byte* gcsp; // if status==Gsyscall, gcsp = sched.sp to use during gc
+ byte* gcguard; // if status==Gsyscall, gcguard = stackguard to use during gc
byte* stack0;
byte* entry; // initial function
G* alllink; // on allg
@@ -241,6 +244,7 @@ struct M
void* sehframe;
#endif
};
+
struct Stktop
{
// The offsets of these fields are known to (hard-coded in) libmach.
@@ -580,7 +584,6 @@ int32 runtime·gomaxprocsfunc(int32 n);
void runtime·mapassign(Hmap*, byte*, byte*);
void runtime·mapaccess(Hmap*, byte*, byte*, bool*);
-struct hash_iter* runtime·newmapiterinit(Hmap*);
void runtime·mapiternext(struct hash_iter*);
bool runtime·mapiterkey(struct hash_iter*, void*);
void runtime·mapiterkeyvalue(struct hash_iter*, void*, void*);
@@ -589,7 +592,6 @@ Hmap* runtime·makemap_c(Type*, Type*, int64);
Hchan* runtime·makechan_c(Type*, int64);
void runtime·chansend(Hchan*, void*, bool*);
void runtime·chanrecv(Hchan*, void*, bool*, bool*);
-void runtime·chanclose(Hchan*);
int32 runtime·chanlen(Hchan*);
int32 runtime·chancap(Hchan*);
diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c
index 6f0eea0e7..da4579734 100644
--- a/src/pkg/runtime/symtab.c
+++ b/src/pkg/runtime/symtab.c
@@ -291,7 +291,9 @@ splitpcln(void)
if(f < ef && pc >= (f+1)->entry) {
f->pcln.len = p - f->pcln.array;
f->pcln.cap = f->pcln.len;
- f++;
+ do
+ f++;
+ while(f < ef && pc >= (f+1)->entry);
f->pcln.array = p;
// pc0 and ln0 are the starting values for
// the loop over f->pcln, so pc must be
diff --git a/src/pkg/runtime/type.go b/src/pkg/runtime/type.go
index 71ad4e7a5..30f3ec642 100644
--- a/src/pkg/runtime/type.go
+++ b/src/pkg/runtime/type.go
@@ -117,8 +117,9 @@ type UnsafePointerType commonType
// ArrayType represents a fixed array type.
type ArrayType struct {
commonType
- elem *Type // array element type
- len uintptr
+ elem *Type // array element type
+ slice *Type // slice type
+ len uintptr
}
// SliceType represents a slice type.
diff --git a/src/pkg/runtime/windows/thread.c b/src/pkg/runtime/windows/thread.c
index aedd24200..2ce92dcfb 100644
--- a/src/pkg/runtime/windows/thread.c
+++ b/src/pkg/runtime/windows/thread.c
@@ -378,3 +378,9 @@ runtime·compilecallback(Eface fn, bool cleanstack)
return ret;
}
+
+void
+os·sigpipe(void)
+{
+ runtime·throw("too many writes on closed pipe");
+}