tsan: add ReleaseStore() function that merely copies vector clock rather than combines two clocks

fix clock setup for finalizer goroutine (Go runtime)

llvm-svn: 160918
This commit is contained in:
Dmitry Vyukov 2012-07-28 15:27:41 +00:00
parent 44f9b5343d
commit 904d3f9c06
8 changed files with 31 additions and 7 deletions

View File

@ -74,5 +74,5 @@ echo as gotsan.s -o race_$SUFFIX.syso
as gotsan.s -o race_$SUFFIX.syso as gotsan.s -o race_$SUFFIX.syso
gcc test.c race_$SUFFIX.syso -lpthread -o test gcc test.c race_$SUFFIX.syso -lpthread -o test
./test TSAN_OPTIONS="exitcode=0" ./test

View File

@ -46,7 +46,6 @@ int main(void) {
__tsan_read(0, buf, 0); __tsan_read(0, buf, 0);
__tsan_free(buf); __tsan_free(buf);
__tsan_func_exit(0); __tsan_func_exit(0);
printf("OK\n");
__tsan_fini(); __tsan_fini();
return 0; return 0;
} }

View File

@ -165,7 +165,7 @@ void __tsan_acquire(int goid, void *addr) {
void __tsan_release(int goid, void *addr) { void __tsan_release(int goid, void *addr) {
ThreadState *thr = goroutines[goid]; ThreadState *thr = goroutines[goid];
thr->in_rtl++; thr->in_rtl++;
Release(thr, 0, (uptr)addr); ReleaseStore(thr, 0, (uptr)addr);
thr->in_rtl--; thr->in_rtl--;
} }
@ -173,7 +173,6 @@ void __tsan_release_merge(int goid, void *addr) {
ThreadState *thr = goroutines[goid]; ThreadState *thr = goroutines[goid];
thr->in_rtl++; thr->in_rtl++;
Release(thr, 0, (uptr)addr); Release(thr, 0, (uptr)addr);
//ReleaseMerge(thr, 0, (uptr)addr);
thr->in_rtl--; thr->in_rtl--;
} }

View File

@ -88,14 +88,28 @@ void ThreadClock::release(SyncClock *dst) const {
} }
} }
void ThreadClock::ReleaseStore(SyncClock *dst) const {
DCHECK(nclk_ <= kMaxTid);
DCHECK(dst->clk_.Size() <= kMaxTid);
if (dst->clk_.Size() < nclk_)
dst->clk_.Resize(nclk_);
for (uptr i = 0; i < nclk_; i++)
dst->clk_[i] = clk_[i];
for (uptr i = nclk_; i < dst->clk_.Size(); i++)
dst->clk_[i] = 0;
}
void ThreadClock::acq_rel(SyncClock *dst) { void ThreadClock::acq_rel(SyncClock *dst) {
acquire(dst); acquire(dst);
release(dst); release(dst);
} }
void ThreadClock::Disable() { void ThreadClock::Disable(unsigned tid) {
u64 c0 = clk_[tid];
for (uptr i = 0; i < kMaxTidInClock; i++) for (uptr i = 0; i < kMaxTidInClock; i++)
clk_[i] = (u64)-1; clk_[i] = (u64)-1;
clk_[tid] = c0;
} }
SyncClock::SyncClock() SyncClock::SyncClock()

View File

@ -61,7 +61,7 @@ struct ThreadClock {
nclk_ = tid + 1; nclk_ = tid + 1;
} }
void Disable(); void Disable(unsigned tid);
uptr size() const { uptr size() const {
return nclk_; return nclk_;
@ -70,6 +70,7 @@ struct ThreadClock {
void acquire(const SyncClock *src); void acquire(const SyncClock *src);
void release(SyncClock *dst) const; void release(SyncClock *dst) const;
void acq_rel(SyncClock *dst); void acq_rel(SyncClock *dst);
void ReleaseStore(SyncClock *dst) const;
private: private:
uptr nclk_; uptr nclk_;

View File

@ -449,6 +449,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr);
void Acquire(ThreadState *thr, uptr pc, uptr addr); void Acquire(ThreadState *thr, uptr pc, uptr addr);
void Release(ThreadState *thr, uptr pc, uptr addr); void Release(ThreadState *thr, uptr pc, uptr addr);
void ReleaseStore(ThreadState *thr, uptr pc, uptr addr);
// The hacky call uses custom calling convention and an assembly thunk. // The hacky call uses custom calling convention and an assembly thunk.
// It is considerably faster that a normal call for the caller // It is considerably faster that a normal call for the caller

View File

@ -207,4 +207,14 @@ void Release(ThreadState *thr, uptr pc, uptr addr) {
s->mtx.Unlock(); s->mtx.Unlock();
} }
void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) {
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr);
SyncVar *s = CTX()->synctab.GetAndLock(thr, pc, addr, true);
thr->clock.set(thr->tid, thr->fast_state.epoch());
thr->clock.ReleaseStore(&s->clock);
StatInc(thr, StatSyncRelease);
s->mtx.Unlock();
}
} // namespace __tsan } // namespace __tsan

View File

@ -299,7 +299,7 @@ void ThreadDetach(ThreadState *thr, uptr pc, int tid) {
} }
void ThreadFinalizerGoroutine(ThreadState *thr) { void ThreadFinalizerGoroutine(ThreadState *thr) {
thr->clock.Disable(); thr->clock.Disable(thr->tid);
} }
void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr, void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,