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:
parent
44f9b5343d
commit
904d3f9c06
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue