Skip to content

Commit

Permalink
tsan: unify __cxa_guard_acquire and pthread_once implementations
Browse files Browse the repository at this point in the history
Currently we effectively duplicate "once" logic for __cxa_guard_acquire
and pthread_once. Unify the implementations.

This is not a no-op change:
 - constants used for pthread_once are changed to match __cxa_guard_acquire
   (__cxa_guard_acquire constants are tied to ABI, but it does not seem
   to be the case for pthread_once)
 - pthread_once now also uses PotentiallyBlockingRegion annotations
 - __cxa_guard_acquire checks thr->in_ignored_lib to skip user synchronization
It's unclear if these 2 differences are intentional or a mere sloppy inconsistency.
Since all tests still pass, let's assume the latter.

Reviewed By: vitalybuka, melver

Differential Revision: https://reviews.llvm.org/D107359
  • Loading branch information
dvyukov committed Aug 4, 2021
1 parent 14e306f commit 636428c
Showing 1 changed file with 29 additions and 29 deletions.
58 changes: 29 additions & 29 deletions compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,31 @@ TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) {
}
#endif

static int guard_acquire(ThreadState *thr, uptr pc, atomic_uint32_t *g) {
OnPotentiallyBlockingRegionBegin();
auto on_exit = at_scope_exit(&OnPotentiallyBlockingRegionEnd);
for (;;) {
u32 cmp = atomic_load(g, memory_order_acquire);
if (cmp == 0) {
if (atomic_compare_exchange_strong(g, &cmp, 1 << 16,
memory_order_relaxed))
return 1;
} else if (cmp == 1) {
if (!thr->in_ignored_lib)
Acquire(thr, pc, (uptr)g);
return 0;
} else {
internal_sched_yield();
}
}
}

static void guard_release(ThreadState *thr, uptr pc, atomic_uint32_t *g) {
if (!thr->in_ignored_lib)
Release(thr, pc, (uptr)g);
atomic_store(g, 1, memory_order_release);
}

// __cxa_guard_acquire and friends need to be intercepted in a special way -
// regular interceptors will break statically-linked libstdc++. Linux
// interceptors are especially defined as weak functions (so that they don't
Expand All @@ -864,26 +889,12 @@ TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) {
// Used in thread-safe function static initialization.
STDCXX_INTERCEPTOR(int, __cxa_guard_acquire, atomic_uint32_t *g) {
SCOPED_INTERCEPTOR_RAW(__cxa_guard_acquire, g);
OnPotentiallyBlockingRegionBegin();
auto on_exit = at_scope_exit(&OnPotentiallyBlockingRegionEnd);
for (;;) {
u32 cmp = atomic_load(g, memory_order_acquire);
if (cmp == 0) {
if (atomic_compare_exchange_strong(g, &cmp, 1<<16, memory_order_relaxed))
return 1;
} else if (cmp == 1) {
Acquire(thr, pc, (uptr)g);
return 0;
} else {
internal_sched_yield();
}
}
return guard_acquire(thr, pc, g);
}

STDCXX_INTERCEPTOR(void, __cxa_guard_release, atomic_uint32_t *g) {
SCOPED_INTERCEPTOR_RAW(__cxa_guard_release, g);
Release(thr, pc, (uptr)g);
atomic_store(g, 1, memory_order_release);
guard_release(thr, pc, g);
}

STDCXX_INTERCEPTOR(void, __cxa_guard_abort, atomic_uint32_t *g) {
Expand Down Expand Up @@ -1480,20 +1491,9 @@ TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
else
a = static_cast<atomic_uint32_t*>(o);

u32 v = atomic_load(a, memory_order_acquire);
if (v == 0 && atomic_compare_exchange_strong(a, &v, 1,
memory_order_relaxed)) {
if (guard_acquire(thr, pc, a)) {
(*f)();
if (!thr->in_ignored_lib)
Release(thr, pc, (uptr)o);
atomic_store(a, 2, memory_order_release);
} else {
while (v != 2) {
internal_sched_yield();
v = atomic_load(a, memory_order_acquire);
}
if (!thr->in_ignored_lib)
Acquire(thr, pc, (uptr)o);
guard_release(thr, pc, a);
}
return 0;
}
Expand Down

0 comments on commit 636428c

Please sign in to comment.