2727
2828using namespace __tsan ;
2929
30+ static bool correctRaceDetection (){
31+ return flags ()->correct_race_detection ;
32+ }
33+
3034#if !SANITIZER_GO && __TSAN_HAS_INT128
3135// Protects emulation of 128-bit atomic operations.
3236static StaticSpinMutex mutex128;
@@ -227,18 +231,36 @@ namespace {
227231template <typename T, T (*F)(volatile T *v, T op)>
228232static T AtomicRMW (ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) {
229233 MemoryAccess (thr, pc, (uptr)a, AccessSize<T>(), kAccessWrite | kAccessAtomic );
230- if (LIKELY (mo == mo_relaxed))
231- return F (a, v);
234+ if (!correctRaceDetection ()){
235+ if (LIKELY (mo == mo_relaxed))
236+ return F (a, v);
237+ }
232238 SlotLocker locker (thr);
233239 {
234240 auto s = ctx->metamap .GetSyncOrCreate (thr, pc, (uptr)a, false );
235- RWLock lock (&s->mtx , IsReleaseOrder (mo));
236- if (IsAcqRelOrder (mo))
237- thr->clock .ReleaseAcquire (&s->clock );
238- else if (IsReleaseOrder (mo))
239- thr->clock .Release (&s->clock );
240- else if (IsAcquireOrder (mo))
241- thr->clock .Acquire (s->clock );
241+ bool fullLock = correctRaceDetection () || IsReleaseOrder (mo);
242+ RWLock lock (&s->mtx , fullLock);
243+ if (!correctRaceDetection ()){
244+ if (IsAcqRelOrder (mo))
245+ thr->clock .ReleaseAcquire (&s->clock );
246+ else if (IsReleaseOrder (mo))
247+ thr->clock .Release (&s->clock );
248+ else if (IsAcquireOrder (mo))
249+ thr->clock .Acquire (s->clock );
250+ } else {
251+ if (mo == mo_relaxed){
252+ thr->clockA .Acquire (s->clock );
253+ thr->clockR .Release (&s->clock );
254+ } else if (IsAcqRelOrder (mo)) {
255+ thr->clock .ReleaseAcquire (&s->clock );
256+ } else if (IsReleaseOrder (mo)) {
257+ thr->clockA .Acquire (s->clock );
258+ thr->clock .Release (&s->clock );
259+ } else if (IsAcquireOrder (mo)) {
260+ thr->clock .Acquire (s->clock );
261+ thr->clockR .Release (&s->clock );
262+ }
263+ }
242264 v = F (a, v);
243265 }
244266 if (IsReleaseOrder (mo))
@@ -264,7 +286,7 @@ struct OpLoad {
264286 DCHECK (IsLoadOrder (mo));
265287 // This fast-path is critical for performance.
266288 // Assume the access is atomic.
267- if (!IsAcquireOrder (mo)) {
289+ if (!correctRaceDetection () && ! IsAcquireOrder (mo)) {
268290 MemoryAccess (thr, pc, (uptr)a, AccessSize<T>(),
269291 kAccessRead | kAccessAtomic );
270292 return NoTsanAtomic (mo, a);
@@ -276,7 +298,11 @@ struct OpLoad {
276298 if (s) {
277299 SlotLocker locker (thr);
278300 ReadLock lock (&s->mtx );
279- thr->clock .Acquire (s->clock );
301+ if (IsAcquireOrder (mo)) {
302+ thr->clock .Acquire (s->clock );
303+ } else if (correctRaceDetection ()) {
304+ thr->clockA .Acquire (s->clock );
305+ }
280306 // Re-read under sync mutex because we need a consistent snapshot
281307 // of the value and the clock we acquire.
282308 v = NoTsanAtomic (mo, a);
@@ -309,18 +335,22 @@ struct OpStore {
309335 // Assume the access is atomic.
310336 // Strictly saying even relaxed store cuts off release sequence,
311337 // so must reset the clock.
312- if (!IsReleaseOrder (mo)) {
338+ if (!correctRaceDetection () && ! IsReleaseOrder (mo)) {
313339 NoTsanAtomic (mo, a, v);
314340 return ;
315341 }
316342 SlotLocker locker (thr);
317343 {
318344 auto s = ctx->metamap .GetSyncOrCreate (thr, pc, (uptr)a, false );
319345 Lock lock (&s->mtx );
320- thr->clock .ReleaseStore (&s->clock );
346+ if (IsReleaseOrder (mo))
347+ thr->clock .ReleaseStore (&s->clock );
348+ else if (correctRaceDetection ())
349+ thr->clockR .ReleaseStore (&s->clock );
321350 NoTsanAtomic (mo, a, v);
322351 }
323- IncrementEpoch (thr);
352+ if (IsReleaseOrder (mo))
353+ IncrementEpoch (thr);
324354 }
325355};
326356
@@ -441,7 +471,7 @@ struct OpCAS {
441471
442472 MemoryAccess (thr, pc, (uptr)a, AccessSize<T>(),
443473 kAccessWrite | kAccessAtomic );
444- if (LIKELY (mo == mo_relaxed && fmo == mo_relaxed)) {
474+ if (LIKELY (! correctRaceDetection () && mo == mo_relaxed && fmo == mo_relaxed)) {
445475 T cc = *c;
446476 T pr = func_cas (a, cc, v);
447477 if (pr == cc)
@@ -454,20 +484,36 @@ struct OpCAS {
454484 bool success;
455485 {
456486 auto s = ctx->metamap .GetSyncOrCreate (thr, pc, (uptr)a, false );
457- RWLock lock (&s->mtx , release);
487+ bool fullLock = correctRaceDetection () || release;
488+ RWLock lock (&s->mtx , fullLock);
458489 T cc = *c;
459490 T pr = func_cas (a, cc, v);
460491 success = pr == cc;
461492 if (!success) {
462493 *c = pr;
463494 mo = fmo;
464495 }
465- if (success && IsAcqRelOrder (mo))
466- thr->clock .ReleaseAcquire (&s->clock );
467- else if (success && IsReleaseOrder (mo))
468- thr->clock .Release (&s->clock );
469- else if (IsAcquireOrder (mo))
470- thr->clock .Acquire (s->clock );
496+ if (!correctRaceDetection ()){
497+ if (success && IsAcqRelOrder (mo))
498+ thr->clock .ReleaseAcquire (&s->clock );
499+ else if (success && IsReleaseOrder (mo))
500+ thr->clock .Release (&s->clock );
501+ else if (IsAcquireOrder (mo))
502+ thr->clock .Acquire (s->clock );
503+ } else {
504+ if (!IsAcquireOrder (mo)){
505+ thr->clockA .Acquire (s->clock );
506+ } else {
507+ thr->clock .Acquire (s->clock );
508+ }
509+ if (success){
510+ if (!IsReleaseOrder (mo)){
511+ thr->clockR .Release (&s->clock );
512+ } else {
513+ thr->clock .Release (&s->clock );
514+ }
515+ }
516+ }
471517 }
472518 if (success && release)
473519 IncrementEpoch (thr);
@@ -487,7 +533,19 @@ struct OpFence {
487533 static void NoTsanAtomic (morder mo) { __sync_synchronize (); }
488534
489535 static void Atomic (ThreadState *thr, uptr pc, morder mo) {
490- // FIXME(dvyukov): not implemented.
536+ if (correctRaceDetection ()){
537+ SlotLocker locker (thr);
538+ if (IsAcquireOrder (mo))
539+ thr->clock .Acquire (&thr->clockA );
540+ if (mo == mo_seq_cst){
541+ auto s = ctx->metamap .GetSyncOrCreate (thr, pc, 0 , false );
542+ thr->clock .ReleaseAcquire (&s->clock );
543+ }
544+ if (IsReleaseOrder (mo)){
545+ thr->clockR .Acquire (&thr->clock );
546+ IncrementEpoch (thr);
547+ }
548+ }
491549 __sync_synchronize ();
492550 }
493551};
0 commit comments