From 3efe395788e17f9be556b2570fb0cd9a1ae93796 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 27 Apr 2016 12:30:48 +0000 Subject: [PATCH] tsan: change tsan/Go interface for obtaining the current Processor Current interface assumes that Go calls ProcWire/ProcUnwire to establish the association between thread and proc. With the wisdom of hindsight, this interface does not work very well. I had to sprinkle Go scheduler with wire/unwire calls, and any mistake leads to hard to debug crashes. This is not something one wants to maintian. Fortunately, there is a simpler solution. We can ask Go runtime as to what is the current Processor, and that question is very easy to answer on Go side. Switch to such interface. llvm-svn: 267703 --- compiler-rt/lib/tsan/go/test.c | 25 +++++++----- compiler-rt/lib/tsan/go/tsan_go.cc | 47 ++++++++++++----------- compiler-rt/lib/tsan/rtl/tsan_interceptors.cc | 4 +- compiler-rt/lib/tsan/rtl/tsan_interface_java.cc | 2 +- compiler-rt/lib/tsan/rtl/tsan_mman.cc | 16 ++++---- compiler-rt/lib/tsan/rtl/tsan_rtl.h | 7 +++- compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc | 14 +++---- compiler-rt/lib/tsan/rtl/tsan_rtl_proc.cc | 8 ++-- compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc | 6 +-- compiler-rt/lib/tsan/rtl/tsan_sync.cc | 8 ++-- compiler-rt/lib/tsan/tests/unit/tsan_sync_test.cc | 14 +++---- 11 files changed, 82 insertions(+), 69 deletions(-) diff --git a/compiler-rt/lib/tsan/go/test.c b/compiler-rt/lib/tsan/go/test.c index e59cca3..51ccf29 100644 --- a/compiler-rt/lib/tsan/go/test.c +++ b/compiler-rt/lib/tsan/go/test.c @@ -27,12 +27,21 @@ void __tsan_write(void *thr, void *addr, void *pc); void __tsan_func_enter(void *thr, void *pc); void __tsan_func_exit(void *thr); void __tsan_malloc(void *thr, void *pc, void *p, unsigned long sz); -void __tsan_free(void *proc, void *p, unsigned long sz); +void __tsan_free(void *p, unsigned long sz); void __tsan_acquire(void *thr, void *addr); void __tsan_release(void *thr, void *addr); void __tsan_release_merge(void *thr, void *addr); -void symbolize_cb(long cmd, void *ctx) {} +void *current_proc; + +void symbolize_cb(long cmd, void *ctx) { + switch (cmd) { + case 0: + if (current_proc == 0) + abort(); + *(void**)ctx = current_proc; + } +} char buf0[100<<10]; @@ -43,11 +52,11 @@ int main(void) { void *thr0 = 0; void *proc0 = 0; __tsan_init(&thr0, &proc0, symbolize_cb); + current_proc = proc0; char *buf = (char*)((unsigned long)buf0 + (64<<10) - 1 & ~((64<<10) - 1)); __tsan_map_shadow(buf, 4096); __tsan_malloc(thr0, (char*)&barfoo + 1, buf, 10); - __tsan_free(proc0, buf, 10); - __tsan_free(thr0, buf, 10); + __tsan_free(buf, 10); __tsan_func_enter(thr0, (char*)&main + 1); __tsan_malloc(thr0, (char*)&barfoo + 1, buf, 10); __tsan_release(thr0, buf); @@ -57,8 +66,6 @@ int main(void) { void *thr2 = 0; __tsan_go_start(thr0, &thr2, (char*)&barfoo + 1); __tsan_func_exit(thr0); - __tsan_proc_unwire(proc0, thr0); - __tsan_proc_wire(proc0, thr1); __tsan_func_enter(thr1, (char*)&foobar + 1); __tsan_func_enter(thr1, (char*)&foobar + 1); __tsan_write(thr1, buf, (char*)&barfoo + 1); @@ -68,14 +75,14 @@ int main(void) { __tsan_go_end(thr1); void *proc1 = 0; __tsan_proc_create(&proc1); - __tsan_proc_wire(proc1, thr2); + current_proc = proc1; __tsan_func_enter(thr2, (char*)&foobar + 1); __tsan_read(thr2, buf, (char*)&barfoo + 1); - __tsan_free(proc1, buf, 10); + __tsan_free(buf, 10); __tsan_func_exit(thr2); __tsan_go_end(thr2); - __tsan_proc_destroy(proc0); __tsan_proc_destroy(proc1); + current_proc = proc0; __tsan_fini(); return 0; } diff --git a/compiler-rt/lib/tsan/go/tsan_go.cc b/compiler-rt/lib/tsan/go/tsan_go.cc index 390c1b4..bc0d553 100644 --- a/compiler-rt/lib/tsan/go/tsan_go.cc +++ b/compiler-rt/lib/tsan/go/tsan_go.cc @@ -40,8 +40,9 @@ void internal_free(void *p) { static void (*go_runtime_cb)(uptr cmd, void *ctx); enum { - CallbackSymbolizeCode = 0, - CallbackSymbolizeData = 1, + CallbackGetProc = 0, + CallbackSymbolizeCode = 1, + CallbackSymbolizeData = 2, }; struct SymbolizeCodeContext { @@ -109,11 +110,27 @@ ReportLocation *SymbolizeData(uptr addr) { } } -extern "C" { - static ThreadState *main_thr; static bool inited; +static Processor* get_cur_proc() { + if (UNLIKELY(!inited)) { + // Running Initialize(). + // We have not yet returned the Processor to Go, so we cannot ask it back. + // Currently, Initialize() does not use the Processor, so return nullptr. + return nullptr; + } + Processor *proc; + go_runtime_cb(CallbackGetProc, &proc); + return proc; +} + +Processor *ThreadState::proc() { + return get_cur_proc(); +} + +extern "C" { + static ThreadState *AllocGoroutine() { ThreadState *thr = (ThreadState*)internal_alloc(MBlockThreadContex, sizeof(ThreadState)); @@ -127,7 +144,7 @@ void __tsan_init(ThreadState **thrp, Processor **procp, ThreadState *thr = AllocGoroutine(); main_thr = *thrp = thr; Initialize(thr); - *procp = thr->proc; + *procp = thr->proc1; inited = true; } @@ -189,27 +206,19 @@ void __tsan_malloc(ThreadState *thr, uptr pc, uptr p, uptr sz) { MemoryResetRange(0, 0, (uptr)p, sz); } -void __tsan_free(Processor *proc, uptr p, uptr sz) { - ctx->metamap.FreeRange(proc, p, sz); +void __tsan_free(uptr p, uptr sz) { + ctx->metamap.FreeRange(get_cur_proc(), p, sz); } void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) { ThreadState *thr = AllocGoroutine(); *pthr = thr; int goid = ThreadCreate(parent, (uptr)pc, 0, true); - Processor *proc = parent->proc; - // Temporary borrow proc to handle goroutine start. - ProcUnwire(proc, parent); - ProcWire(proc, thr); ThreadStart(thr, goid, 0); - ProcUnwire(proc, thr); - ProcWire(proc, parent); } void __tsan_go_end(ThreadState *thr) { - Processor *proc = thr->proc; ThreadFinish(thr); - ProcUnwire(proc, thr); internal_free(thr); } @@ -221,14 +230,6 @@ void __tsan_proc_destroy(Processor *proc) { ProcDestroy(proc); } -void __tsan_proc_wire(Processor *proc, ThreadState *thr) { - ProcWire(proc, thr); -} - -void __tsan_proc_unwire(Processor *proc, ThreadState *thr) { - ProcUnwire(proc, thr); -} - void __tsan_acquire(ThreadState *thr, void *addr) { Acquire(thr, 0, (uptr)addr); } diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc index abc73d0..4639989 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc @@ -740,7 +740,7 @@ TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) { if (sz != 0) { // If sz == 0, munmap will return EINVAL and don't unmap any memory. DontNeedShadowFor((uptr)addr, sz); - ctx->metamap.ResetRange(thr->proc, (uptr)addr, (uptr)sz); + ctx->metamap.ResetRange(thr->proc(), (uptr)addr, (uptr)sz); } int res = REAL(munmap)(addr, sz); return res; @@ -835,7 +835,7 @@ STDCXX_INTERCEPTOR(void, __cxa_guard_abort, atomic_uint32_t *g) { namespace __tsan { void DestroyThreadState() { ThreadState *thr = cur_thread(); - Processor *proc = thr->proc; + Processor *proc = thr->proc(); ThreadFinish(thr); ProcUnwire(proc, thr); ProcDestroy(proc); diff --git a/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc b/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc index fd771b4..95be859 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc @@ -111,7 +111,7 @@ void __tsan_java_free(jptr ptr, jptr size) { CHECK_GE(ptr, jctx->heap_begin); CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size); - ctx->metamap.FreeRange(thr->proc, ptr, size); + ctx->metamap.FreeRange(thr->proc(), ptr, size); } void __tsan_java_move(jptr src, jptr dst, jptr size) { diff --git a/compiler-rt/lib/tsan/rtl/tsan_mman.cc b/compiler-rt/lib/tsan/rtl/tsan_mman.cc index 9e31a9d..255187b 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_mman.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_mman.cc @@ -98,7 +98,7 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) { void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) { if ((sz >= (1ull << 40)) || (align >= (1ull << 40))) return allocator()->ReturnNullOrDie(); - void *p = allocator()->Allocate(&thr->proc->alloc_cache, sz, align); + void *p = allocator()->Allocate(&thr->proc()->alloc_cache, sz, align); if (p == 0) return 0; if (ctx && ctx->initialized) @@ -120,7 +120,7 @@ void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) { void user_free(ThreadState *thr, uptr pc, void *p, bool signal) { if (ctx && ctx->initialized) OnUserFree(thr, pc, (uptr)p, true); - allocator()->Deallocate(&thr->proc->alloc_cache, p); + allocator()->Deallocate(&thr->proc()->alloc_cache, p); if (signal) SignalUnsafeCall(thr, pc); } @@ -136,7 +136,7 @@ void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write) { void OnUserFree(ThreadState *thr, uptr pc, uptr p, bool write) { CHECK_NE(p, (void*)0); - uptr sz = ctx->metamap.FreeBlock(thr->proc, p); + uptr sz = ctx->metamap.FreeBlock(thr->proc(), p); DPrintf("#%d: free(%p, %zu)\n", thr->tid, p, sz); if (write && thr->ignore_reads_and_writes == 0) MemoryRangeFreed(thr, pc, (uptr)p, sz); @@ -187,7 +187,7 @@ void *internal_alloc(MBlockType typ, uptr sz) { thr->nomalloc = 0; // CHECK calls internal_malloc(). CHECK(0); } - return InternalAlloc(sz, &thr->proc->internal_alloc_cache); + return InternalAlloc(sz, &thr->proc()->internal_alloc_cache); } void internal_free(void *p) { @@ -196,7 +196,7 @@ void internal_free(void *p) { thr->nomalloc = 0; // CHECK calls internal_malloc(). CHECK(0); } - InternalFree(p, &thr->proc->internal_alloc_cache); + InternalFree(p, &thr->proc()->internal_alloc_cache); } } // namespace __tsan @@ -238,8 +238,8 @@ uptr __sanitizer_get_allocated_size(const void *p) { void __tsan_on_thread_idle() { ThreadState *thr = cur_thread(); - allocator()->SwallowCache(&thr->proc->alloc_cache); - internal_allocator()->SwallowCache(&thr->proc->internal_alloc_cache); - ctx->metamap.OnProcIdle(thr->proc); + allocator()->SwallowCache(&thr->proc()->alloc_cache); + internal_allocator()->SwallowCache(&thr->proc()->internal_alloc_cache); + ctx->metamap.OnProcIdle(thr->proc()); } } // extern "C" diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h index ad3e24e..aa81815 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h @@ -406,7 +406,12 @@ struct ThreadState { DDLogicalThread *dd_lt; // Current wired Processor, or nullptr. Required to handle any events. - Processor *proc; + Processor *proc1; +#ifndef SANITIZER_GO + Processor *proc() { return proc1; } +#else + Processor *proc(); +#endif atomic_uintptr_t in_signal_handler; ThreadSignalContext *signal_ctx; diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc index 5266cee..b5125b3 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc @@ -32,7 +32,7 @@ struct Callback : DDCallback { Callback(ThreadState *thr, uptr pc) : thr(thr) , pc(pc) { - DDCallback::pt = thr->proc->dd_pt; + DDCallback::pt = thr->proc()->dd_pt; DDCallback::lt = thr->dd_lt; } @@ -114,7 +114,7 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) { u64 mid = s->GetId(); u32 last_lock = s->last_lock; if (!unlock_locked) - s->Reset(thr->proc); // must not reset it before the report is printed + s->Reset(thr->proc()); // must not reset it before the report is printed s->mtx.Unlock(); if (unlock_locked) { ThreadRegistryLock l(ctx->thread_registry); @@ -132,7 +132,7 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) { if (unlock_locked) { SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr); if (s != 0) { - s->Reset(thr->proc); + s->Reset(thr->proc()); s->mtx.Unlock(); } } @@ -434,7 +434,7 @@ void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) { if (thr->ignore_sync) return; thr->clock.set(thr->fast_state.epoch()); - thr->clock.acquire(&thr->proc->clock_cache, c); + thr->clock.acquire(&thr->proc()->clock_cache, c); StatInc(thr, StatSyncAcquire); } @@ -443,7 +443,7 @@ void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) { return; thr->clock.set(thr->fast_state.epoch()); thr->fast_synch_epoch = thr->fast_state.epoch(); - thr->clock.release(&thr->proc->clock_cache, c); + thr->clock.release(&thr->proc()->clock_cache, c); StatInc(thr, StatSyncRelease); } @@ -452,7 +452,7 @@ void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c) { return; thr->clock.set(thr->fast_state.epoch()); thr->fast_synch_epoch = thr->fast_state.epoch(); - thr->clock.ReleaseStore(&thr->proc->clock_cache, c); + thr->clock.ReleaseStore(&thr->proc()->clock_cache, c); StatInc(thr, StatSyncRelease); } @@ -461,7 +461,7 @@ void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) { return; thr->clock.set(thr->fast_state.epoch()); thr->fast_synch_epoch = thr->fast_state.epoch(); - thr->clock.acq_rel(&thr->proc->clock_cache, c); + thr->clock.acq_rel(&thr->proc()->clock_cache, c); StatInc(thr, StatSyncAcquire); StatInc(thr, StatSyncRelease); } diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_proc.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_proc.cc index c396350..0c838a1 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl_proc.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_proc.cc @@ -45,16 +45,16 @@ void ProcDestroy(Processor *proc) { } void ProcWire(Processor *proc, ThreadState *thr) { - CHECK_EQ(thr->proc, nullptr); + CHECK_EQ(thr->proc1, nullptr); CHECK_EQ(proc->thr, nullptr); - thr->proc = proc; + thr->proc1 = proc; proc->thr = thr; } void ProcUnwire(Processor *proc, ThreadState *thr) { - CHECK_EQ(thr->proc, proc); + CHECK_EQ(thr->proc1, proc); CHECK_EQ(proc->thr, thr); - thr->proc = nullptr; + thr->proc1 = nullptr; proc->thr = nullptr; } diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc index 353e086..ab8f3c3 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc @@ -42,7 +42,7 @@ void ThreadContext::OnDead() { void ThreadContext::OnJoined(void *arg) { ThreadState *caller_thr = static_cast(arg); AcquireImpl(caller_thr, 0, &sync); - sync.Reset(&caller_thr->proc->clock_cache); + sync.Reset(&caller_thr->proc()->clock_cache); } struct OnCreatedArgs { @@ -74,7 +74,7 @@ void ThreadContext::OnReset() { void ThreadContext::OnDetached(void *arg) { ThreadState *thr1 = static_cast(arg); - sync.Reset(&thr1->proc->clock_cache); + sync.Reset(&thr1->proc()->clock_cache); } struct OnStartedArgs { @@ -116,7 +116,7 @@ void ThreadContext::OnStarted(void *arg) { thr->fast_synch_epoch = epoch0; AcquireImpl(thr, 0, &sync); StatInc(thr, StatSyncAcquire); - sync.Reset(&thr->proc->clock_cache); + sync.Reset(&thr->proc()->clock_cache); thr->is_inited = true; DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx " "tls_addr=%zx tls_size=%zx\n", diff --git a/compiler-rt/lib/tsan/rtl/tsan_sync.cc b/compiler-rt/lib/tsan/rtl/tsan_sync.cc index 4a85e61..c58821a 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_sync.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_sync.cc @@ -61,7 +61,7 @@ MetaMap::MetaMap() { } void MetaMap::AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz) { - u32 idx = block_alloc_.Alloc(&thr->proc->block_cache); + u32 idx = block_alloc_.Alloc(&thr->proc()->block_cache); MBlock *b = block_alloc_.Map(idx); b->siz = sz; b->tid = thr->tid; @@ -210,8 +210,8 @@ SyncVar* MetaMap::GetAndLock(ThreadState *thr, uptr pc, SyncVar * s = sync_alloc_.Map(idx & ~kFlagMask); if (s->addr == addr) { if (myidx != 0) { - mys->Reset(thr->proc); - sync_alloc_.Free(&thr->proc->sync_cache, myidx); + mys->Reset(thr->proc()); + sync_alloc_.Free(&thr->proc()->sync_cache, myidx); } if (write_lock) s->mtx.Lock(); @@ -230,7 +230,7 @@ SyncVar* MetaMap::GetAndLock(ThreadState *thr, uptr pc, if (myidx == 0) { const u64 uid = atomic_fetch_add(&uid_gen_, 1, memory_order_relaxed); - myidx = sync_alloc_.Alloc(&thr->proc->sync_cache); + myidx = sync_alloc_.Alloc(&thr->proc()->sync_cache); mys = sync_alloc_.Map(myidx); mys->Init(thr, pc, addr, uid); } diff --git a/compiler-rt/lib/tsan/tests/unit/tsan_sync_test.cc b/compiler-rt/lib/tsan/tests/unit/tsan_sync_test.cc index 931a33b..9e57a37 100644 --- a/compiler-rt/lib/tsan/tests/unit/tsan_sync_test.cc +++ b/compiler-rt/lib/tsan/tests/unit/tsan_sync_test.cc @@ -25,7 +25,7 @@ TEST(MetaMap, Basic) { EXPECT_NE(mb, (MBlock*)0); EXPECT_EQ(mb->siz, 1 * sizeof(u64)); EXPECT_EQ(mb->tid, thr->tid); - uptr sz = m->FreeBlock(thr->proc, (uptr)&block[0]); + uptr sz = m->FreeBlock(thr->proc(), (uptr)&block[0]); EXPECT_EQ(sz, 1 * sizeof(u64)); mb = m->GetBlock((uptr)&block[0]); EXPECT_EQ(mb, (MBlock*)0); @@ -41,7 +41,7 @@ TEST(MetaMap, FreeRange) { EXPECT_EQ(mb1->siz, 1 * sizeof(u64)); MBlock *mb2 = m->GetBlock((uptr)&block[1]); EXPECT_EQ(mb2->siz, 3 * sizeof(u64)); - m->FreeRange(thr->proc, (uptr)&block[0], 4 * sizeof(u64)); + m->FreeRange(thr->proc(), (uptr)&block[0], 4 * sizeof(u64)); mb1 = m->GetBlock((uptr)&block[0]); EXPECT_EQ(mb1, (MBlock*)0); mb2 = m->GetBlock((uptr)&block[1]); @@ -63,12 +63,12 @@ TEST(MetaMap, Sync) { EXPECT_NE(s2, (SyncVar*)0); EXPECT_EQ(s2->addr, (uptr)&block[1]); s2->mtx.ReadUnlock(); - m->FreeBlock(thr->proc, (uptr)&block[0]); + m->FreeBlock(thr->proc(), (uptr)&block[0]); s1 = m->GetIfExistsAndLock((uptr)&block[0]); EXPECT_EQ(s1, (SyncVar*)0); s2 = m->GetIfExistsAndLock((uptr)&block[1]); EXPECT_EQ(s2, (SyncVar*)0); - m->OnProcIdle(thr->proc); + m->OnProcIdle(thr->proc()); } TEST(MetaMap, MoveMemory) { @@ -105,7 +105,7 @@ TEST(MetaMap, MoveMemory) { EXPECT_NE(s2, (SyncVar*)0); EXPECT_EQ(s2->addr, (uptr)&block2[1]); s2->mtx.Unlock(); - m->FreeRange(thr->proc, (uptr)&block2[0], 4 * sizeof(u64)); + m->FreeRange(thr->proc(), (uptr)&block2[0], 4 * sizeof(u64)); } TEST(MetaMap, ResetSync) { @@ -114,9 +114,9 @@ TEST(MetaMap, ResetSync) { u64 block[1] = {}; // fake malloc block m->AllocBlock(thr, 0, (uptr)&block[0], 1 * sizeof(u64)); SyncVar *s = m->GetOrCreateAndLock(thr, 0, (uptr)&block[0], true); - s->Reset(thr->proc); + s->Reset(thr->proc()); s->mtx.Unlock(); - uptr sz = m->FreeBlock(thr->proc, (uptr)&block[0]); + uptr sz = m->FreeBlock(thr->proc(), (uptr)&block[0]); EXPECT_EQ(sz, 1 * sizeof(u64)); } -- 2.7.4