Index: compiler-rt/lib/tsan/go/tsan_go.cpp =================================================================== --- compiler-rt/lib/tsan/go/tsan_go.cpp +++ compiler-rt/lib/tsan/go/tsan_go.cpp @@ -244,6 +244,10 @@ Acquire(thr, 0, (uptr)addr); } +void __tsan_release_acquire(ThreadState *thr, void *addr) { + ReleaseAcquire(thr, 0, (uptr)addr); +} + void __tsan_release(ThreadState *thr, void *addr) { ReleaseStore(thr, 0, (uptr)addr); } Index: compiler-rt/lib/tsan/rtl/tsan_clock.h =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_clock.h +++ compiler-rt/lib/tsan/rtl/tsan_clock.h @@ -134,6 +134,7 @@ uptr size() const; void acquire(ClockCache *c, SyncClock *src); + void releaseAcquire(ClockCache *c, SyncClock *src); void release(ClockCache *c, SyncClock *dst); void acq_rel(ClockCache *c, SyncClock *dst); void ReleaseStore(ClockCache *c, SyncClock *dst); Index: compiler-rt/lib/tsan/rtl/tsan_clock.cpp =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_clock.cpp +++ compiler-rt/lib/tsan/rtl/tsan_clock.cpp @@ -30,6 +30,14 @@ // dst->clock[i] = max(dst->clock[i], clock[i]); // } // +// void ThreadClock::releaseAcquire(SyncClock *sc) const { +// for (int i = 0; i < kMaxThreads; i++) { +// tmp = clock[i]; +// clock[i] = max(clock[i], sc->clock[i]); +// sc->clock[i] = tmp; +// } +// } +// // void ThreadClock::ReleaseStore(SyncClock *dst) const { // for (int i = 0; i < kMaxThreads; i++) // dst->clock[i] = clock[i]; @@ -177,6 +185,40 @@ } } +void ThreadClock::releaseAcquire(ClockCache *c, SyncClock *sc) { + DCHECK_LE(nclk_, kMaxTid); + DCHECK_LE(dst->size_, kMaxTid); + + if (sc->size_ == 0) { + // ReleaseStore will correctly set release_store_tid_, + // which can be important for future operations. + ReleaseStore(c, sc); + return; + } + + // Check if we need to resize dst. + if (sc->size_ < nclk_) + sc->Resize(c, nclk_); + + sc->Unshare(c); + // First, remember whether we've acquired dst. + bool acquired = IsAlreadyAcquired(sc); + if (acquired) + CPP_STAT_INC(StatClockReleaseAcquired); + // Update sc->clk_. + sc->FlushDirty(); + uptr i = 0; + for (ClockElem &ce : *sc) { + u64 tmp = clk_[i]; + clk_[i] = max(ce.epoch, clk_[i]); + ce.epoch = tmp; + ce.reused = 0; + i++; + } + sc->release_store_tid_ = kInvalidTid; + sc->release_store_reused_ = 0; +} + void ThreadClock::release(ClockCache *c, SyncClock *dst) { DCHECK_LE(nclk_, kMaxTid); DCHECK_LE(dst->size_, kMaxTid); Index: compiler-rt/lib/tsan/rtl/tsan_rtl.h =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_rtl.h +++ compiler-rt/lib/tsan/rtl/tsan_rtl.h @@ -813,10 +813,12 @@ // approximation of the actual required synchronization. void AcquireGlobal(ThreadState *thr, uptr pc); void Release(ThreadState *thr, uptr pc, uptr addr); +void ReleaseAcquire(ThreadState *thr, uptr pc, uptr addr); void ReleaseStore(ThreadState *thr, uptr pc, uptr addr); void AfterSleep(ThreadState *thr, uptr pc); void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c); void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c); +void ReleaseAcquireImpl(ThreadState *thr, uptr pc, SyncClock *c); void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c); void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c); Index: compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp +++ compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp @@ -429,6 +429,18 @@ UpdateClockCallback, thr); } +void ReleaseAcquire(ThreadState *thr, uptr pc, uptr addr) { + DPrintf("#%d: ReleaseAcquire %zx\n", thr->tid, addr); + if (thr->ignore_sync) + return; + SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); + thr->fast_state.IncrementEpoch(); + // Can't increment epoch w/o writing to the trace as well. + TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); + ReleaseAcquireImpl(thr, pc, &s->clock); + s->mtx.Unlock(); +} + void Release(ThreadState *thr, uptr pc, uptr addr) { DPrintf("#%d: Release %zx\n", thr->tid, addr); if (thr->ignore_sync) @@ -482,6 +494,15 @@ StatInc(thr, StatSyncAcquire); } +void ReleaseAcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) { + if (thr->ignore_sync) + return; + thr->clock.set(thr->fast_state.epoch()); + thr->fast_synch_epoch = thr->fast_state.epoch(); + thr->clock.releaseAcquire(&thr->proc()->clock_cache, c); + StatInc(thr, StatSyncReleaseAcquire); +} + void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) { if (thr->ignore_sync) return; Index: compiler-rt/lib/tsan/rtl/tsan_stat.h =================================================================== --- compiler-rt/lib/tsan/rtl/tsan_stat.h +++ compiler-rt/lib/tsan/rtl/tsan_stat.h @@ -68,6 +68,7 @@ StatSyncDestroyed, StatSyncAcquire, StatSyncRelease, + StatSyncReleaseAcquire, // Clocks - acquire. StatClockAcquire,