diff options
Diffstat (limited to 'src/pkg/runtime')
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"); +} |