Commit 0ce96f9e authored by Dmitriy Vyukov's avatar Dmitriy Vyukov

runtime: better stack traces in race reports

When a race happens inside of runtime (chan, slice, etc),
currently reports contain only user file:line.
If the line contains a complex expression,
it's difficult to figure out where the race exactly.
This change adds one more top frame with exact
runtime function (e.g. runtime.chansend, runtime.mapaccess).

R=golang-dev
CC=golang-dev
https://golang.org/cl/6851125
parent c3c107f6
...@@ -188,7 +188,7 @@ runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc) ...@@ -188,7 +188,7 @@ runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
runtime·lock(c); runtime·lock(c);
// TODO(dvyukov): add similar instrumentation to select. // TODO(dvyukov): add similar instrumentation to select.
if(raceenabled) if(raceenabled)
runtime·racereadpc(c, pc); runtime·racereadpc(c, pc, runtime·chansend);
if(c->closed) if(c->closed)
goto closed; goto closed;
...@@ -1193,7 +1193,7 @@ runtime·closechan(Hchan *c) ...@@ -1193,7 +1193,7 @@ runtime·closechan(Hchan *c)
} }
if(raceenabled) { if(raceenabled) {
runtime·racewritepc(c, runtime·getcallerpc(&c)); runtime·racewritepc(c, runtime·getcallerpc(&c), runtime·closechan);
runtime·racerelease(c); runtime·racerelease(c);
} }
......
...@@ -842,7 +842,7 @@ runtime·mapaccess1(MapType *t, Hmap *h, ...) ...@@ -842,7 +842,7 @@ runtime·mapaccess1(MapType *t, Hmap *h, ...)
bool pres; bool pres;
if(raceenabled && h != nil) if(raceenabled && h != nil)
runtime·racereadpc(h, runtime·getcallerpc(&t)); runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapaccess1);
ak = (byte*)(&h + 1); ak = (byte*)(&h + 1);
av = ak + ROUND(t->key->size, Structrnd); av = ak + ROUND(t->key->size, Structrnd);
...@@ -870,7 +870,7 @@ runtime·mapaccess2(MapType *t, Hmap *h, ...) ...@@ -870,7 +870,7 @@ runtime·mapaccess2(MapType *t, Hmap *h, ...)
byte *ak, *av, *ap; byte *ak, *av, *ap;
if(raceenabled && h != nil) if(raceenabled && h != nil)
runtime·racereadpc(h, runtime·getcallerpc(&t)); runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapaccess2);
ak = (byte*)(&h + 1); ak = (byte*)(&h + 1);
av = ak + ROUND(t->key->size, Structrnd); av = ak + ROUND(t->key->size, Structrnd);
...@@ -901,7 +901,7 @@ reflect·mapaccess(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres) ...@@ -901,7 +901,7 @@ reflect·mapaccess(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
byte *ak, *av; byte *ak, *av;
if(raceenabled && h != nil) if(raceenabled && h != nil)
runtime·racereadpc(h, runtime·getcallerpc(&t)); runtime·racereadpc(h, runtime·getcallerpc(&t), reflect·mapaccess);
if(t->key->size <= sizeof(key)) if(t->key->size <= sizeof(key))
ak = (byte*)&key; ak = (byte*)&key;
...@@ -974,7 +974,7 @@ runtime·mapassign1(MapType *t, Hmap *h, ...) ...@@ -974,7 +974,7 @@ runtime·mapassign1(MapType *t, Hmap *h, ...)
runtime·panicstring("assignment to entry in nil map"); runtime·panicstring("assignment to entry in nil map");
if(raceenabled) if(raceenabled)
runtime·racewritepc(h, runtime·getcallerpc(&t)); runtime·racewritepc(h, runtime·getcallerpc(&t), runtime·mapassign1);
ak = (byte*)(&h + 1); ak = (byte*)(&h + 1);
av = ak + ROUND(t->key->size, t->elem->align); av = ak + ROUND(t->key->size, t->elem->align);
...@@ -992,7 +992,7 @@ runtime·mapdelete(MapType *t, Hmap *h, ...) ...@@ -992,7 +992,7 @@ runtime·mapdelete(MapType *t, Hmap *h, ...)
runtime·panicstring("deletion of entry in nil map"); runtime·panicstring("deletion of entry in nil map");
if(raceenabled) if(raceenabled)
runtime·racewritepc(h, runtime·getcallerpc(&t)); runtime·racewritepc(h, runtime·getcallerpc(&t), runtime·mapdelete);
ak = (byte*)(&h + 1); ak = (byte*)(&h + 1);
runtime·mapassign(t, h, ak, nil); runtime·mapassign(t, h, ak, nil);
...@@ -1017,7 +1017,7 @@ reflect·mapassign(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres) ...@@ -1017,7 +1017,7 @@ reflect·mapassign(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
if(h == nil) if(h == nil)
runtime·panicstring("assignment to entry in nil map"); runtime·panicstring("assignment to entry in nil map");
if(raceenabled) if(raceenabled)
runtime·racewritepc(h, runtime·getcallerpc(&t)); runtime·racewritepc(h, runtime·getcallerpc(&t), reflect·mapassign);
if(t->key->size <= sizeof(key)) if(t->key->size <= sizeof(key))
ak = (byte*)&key; ak = (byte*)&key;
else else
...@@ -1040,7 +1040,7 @@ runtime·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it) ...@@ -1040,7 +1040,7 @@ runtime·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
return; return;
} }
if(raceenabled) if(raceenabled)
runtime·racereadpc(h, runtime·getcallerpc(&t)); runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapiterinit);
hash_iter_init(t, h, it); hash_iter_init(t, h, it);
it->data = hash_next(it); it->data = hash_next(it);
if(debug) { if(debug) {
...@@ -1085,7 +1085,7 @@ void ...@@ -1085,7 +1085,7 @@ void
runtime·mapiternext(struct hash_iter *it) runtime·mapiternext(struct hash_iter *it)
{ {
if(raceenabled) if(raceenabled)
runtime·racereadpc(it->h, runtime·getcallerpc(&it)); runtime·racereadpc(it->h, runtime·getcallerpc(&it), runtime·mapiternext);
if(runtime·gcwaiting) if(runtime·gcwaiting)
runtime·gosched(); runtime·gosched();
...@@ -1190,7 +1190,7 @@ reflect·maplen(Hmap *h, intgo len) ...@@ -1190,7 +1190,7 @@ reflect·maplen(Hmap *h, intgo len)
else { else {
len = h->count; len = h->count;
if(raceenabled) if(raceenabled)
runtime·racereadpc(h, runtime·getcallerpc(&h)); runtime·racereadpc(h, runtime·getcallerpc(&h), reflect·maplen);
} }
FLUSH(&len); FLUSH(&len);
} }
......
...@@ -152,24 +152,40 @@ runtime·racegoend(int32 goid) ...@@ -152,24 +152,40 @@ runtime·racegoend(int32 goid)
m->racecall = false; m->racecall = false;
} }
void static void
runtime·racewritepc(void *addr, void *pc) memoryaccess(void *addr, uintptr callpc, uintptr pc, bool write)
{ {
int64 goid;
if(!onstack((uintptr)addr)) { if(!onstack((uintptr)addr)) {
m->racecall = true; m->racecall = true;
runtimerace·Write(g->goid-1, addr, pc); goid = g->goid-1;
if(callpc) {
if(callpc == (uintptr)runtime·lessstack ||
(callpc >= (uintptr)runtime·mheap.arena_start && callpc < (uintptr)runtime·mheap.arena_used))
runtime·callers(3, &callpc, 1);
runtimerace·FuncEnter(goid, (void*)callpc);
}
if(write)
runtimerace·Write(goid, addr, (void*)pc);
else
runtimerace·Read(goid, addr, (void*)pc);
if(callpc)
runtimerace·FuncExit(goid);
m->racecall = false; m->racecall = false;
} }
} }
void void
runtime·racereadpc(void *addr, void *pc) runtime·racewritepc(void *addr, void *callpc, void *pc)
{ {
if(!onstack((uintptr)addr)) { memoryaccess(addr, (uintptr)callpc, (uintptr)pc, true);
m->racecall = true; }
runtimerace·Read(g->goid-1, addr, pc);
m->racecall = false; void
} runtime·racereadpc(void *addr, void *callpc, void *pc)
{
memoryaccess(addr, (uintptr)callpc, (uintptr)pc, false);
} }
void void
...@@ -266,7 +282,7 @@ void runtime·RaceSemrelease(uint32 *s) ...@@ -266,7 +282,7 @@ void runtime·RaceSemrelease(uint32 *s)
void void
runtime·RaceRead(void *addr) runtime·RaceRead(void *addr)
{ {
runtime·racereadpc(addr, runtime·getcallerpc(&addr)); memoryaccess(addr, 0, (uintptr)runtime·getcallerpc(&addr), false);
} }
// func RaceWrite(addr unsafe.Pointer) // func RaceWrite(addr unsafe.Pointer)
...@@ -274,7 +290,7 @@ runtime·RaceRead(void *addr) ...@@ -274,7 +290,7 @@ runtime·RaceRead(void *addr)
void void
runtime·RaceWrite(void *addr) runtime·RaceWrite(void *addr)
{ {
runtime·racewritepc(addr, runtime·getcallerpc(&addr)); memoryaccess(addr, 0, (uintptr)runtime·getcallerpc(&addr), true);
} }
// func RaceDisable() // func RaceDisable()
......
...@@ -20,8 +20,8 @@ void runtime·racemalloc(void *p, uintptr sz, void *pc); ...@@ -20,8 +20,8 @@ void runtime·racemalloc(void *p, uintptr sz, void *pc);
void runtime·racefree(void *p); void runtime·racefree(void *p);
void runtime·racegostart(int32 goid, void *pc); void runtime·racegostart(int32 goid, void *pc);
void runtime·racegoend(int32 goid); void runtime·racegoend(int32 goid);
void runtime·racewritepc(void *addr, void *pc); void runtime·racewritepc(void *addr, void *callpc, void *pc);
void runtime·racereadpc(void *addr, void *pc); void runtime·racereadpc(void *addr, void *callpc, void *pc);
void runtime·racefingo(void); void runtime·racefingo(void);
void runtime·raceacquire(void *addr); void runtime·raceacquire(void *addr);
void runtime·raceacquireg(G *gp, void *addr); void runtime·raceacquireg(G *gp, void *addr);
......
...@@ -26,16 +26,18 @@ runtime·racemapshadow(void *addr, uintptr size) ...@@ -26,16 +26,18 @@ runtime·racemapshadow(void *addr, uintptr size)
} }
void void
runtime·racewritepc(void *addr, void *pc) runtime·racewritepc(void *addr, void *callpc, void *pc)
{ {
USED(addr); USED(addr);
USED(callpc);
USED(pc); USED(pc);
} }
void void
runtime·racereadpc(void *addr, void *pc) runtime·racereadpc(void *addr, void *callpc, void *pc)
{ {
USED(addr); USED(addr);
USED(callpc);
USED(pc); USED(pc);
} }
......
...@@ -83,11 +83,11 @@ runtime·appendslice(SliceType *t, Slice x, Slice y, Slice ret) ...@@ -83,11 +83,11 @@ runtime·appendslice(SliceType *t, Slice x, Slice y, Slice ret)
if(raceenabled) { if(raceenabled) {
pc = runtime·getcallerpc(&t); pc = runtime·getcallerpc(&t);
for(i=0; i<x.len; i++) for(i=0; i<x.len; i++)
runtime·racereadpc(x.array + i*t->elem->size, pc); runtime·racereadpc(x.array + i*t->elem->size, pc, runtime·appendslice);
for(i=x.len; i<x.cap; i++) for(i=x.len; i<x.cap; i++)
runtime·racewritepc(x.array + i*t->elem->size, pc); runtime·racewritepc(x.array + i*t->elem->size, pc, runtime·appendslice);
for(i=0; i<y.len; i++) for(i=0; i<y.len; i++)
runtime·racereadpc(y.array + i*t->elem->size, pc); runtime·racereadpc(y.array + i*t->elem->size, pc, runtime·appendslice);
} }
if(m > x.cap) if(m > x.cap)
...@@ -118,9 +118,9 @@ runtime·appendstr(SliceType *t, Slice x, String y, Slice ret) ...@@ -118,9 +118,9 @@ runtime·appendstr(SliceType *t, Slice x, String y, Slice ret)
if(raceenabled) { if(raceenabled) {
pc = runtime·getcallerpc(&t); pc = runtime·getcallerpc(&t);
for(i=0; i<x.len; i++) for(i=0; i<x.len; i++)
runtime·racereadpc(x.array + i*t->elem->size, pc); runtime·racereadpc(x.array + i*t->elem->size, pc, runtime·appendstr);
for(i=x.len; i<x.cap; i++) for(i=x.len; i<x.cap; i++)
runtime·racewritepc(x.array + i*t->elem->size, pc); runtime·racewritepc(x.array + i*t->elem->size, pc, runtime·appendstr);
} }
if(m > x.cap) if(m > x.cap)
...@@ -153,7 +153,7 @@ runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret) ...@@ -153,7 +153,7 @@ runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
if(raceenabled) { if(raceenabled) {
pc = runtime·getcallerpc(&t); pc = runtime·getcallerpc(&t);
for(i=0; i<old.len; i++) for(i=0; i<old.len; i++)
runtime·racewritepc(old.array + i*t->elem->size, pc); runtime·racewritepc(old.array + i*t->elem->size, pc, runtime·growslice);
} }
growslice1(t, old, cap, &ret); growslice1(t, old, cap, &ret);
...@@ -213,8 +213,8 @@ runtime·copy(Slice to, Slice fm, uintptr width, intgo ret) ...@@ -213,8 +213,8 @@ runtime·copy(Slice to, Slice fm, uintptr width, intgo ret)
if(raceenabled) { if(raceenabled) {
pc = runtime·getcallerpc(&to); pc = runtime·getcallerpc(&to);
for(i=0; i<ret; i++) { for(i=0; i<ret; i++) {
runtime·racewritepc(to.array + i*width, pc); runtime·racewritepc(to.array + i*width, pc, runtime·copy);
runtime·racereadpc(fm.array + i*width, pc); runtime·racereadpc(fm.array + i*width, pc, runtime·copy);
} }
} }
...@@ -259,7 +259,7 @@ runtime·slicestringcopy(Slice to, String fm, intgo ret) ...@@ -259,7 +259,7 @@ runtime·slicestringcopy(Slice to, String fm, intgo ret)
if(raceenabled) { if(raceenabled) {
pc = runtime·getcallerpc(&to); pc = runtime·getcallerpc(&to);
for(i=0; i<ret; i++) { for(i=0; i<ret; i++) {
runtime·racewritepc(to.array + i, pc); runtime·racewritepc(to.array + i, pc, runtime·slicestringcopy);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment