Skip to content

Commit 636428c

Browse files
committed
tsan: unify __cxa_guard_acquire and pthread_once implementations
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
1 parent 14e306f commit 636428c

File tree

1 file changed

+29
-29
lines changed

1 file changed

+29
-29
lines changed

Diff for: compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp

+29-29
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,31 @@ TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) {
844844
}
845845
#endif
846846

847+
static int guard_acquire(ThreadState *thr, uptr pc, atomic_uint32_t *g) {
848+
OnPotentiallyBlockingRegionBegin();
849+
auto on_exit = at_scope_exit(&OnPotentiallyBlockingRegionEnd);
850+
for (;;) {
851+
u32 cmp = atomic_load(g, memory_order_acquire);
852+
if (cmp == 0) {
853+
if (atomic_compare_exchange_strong(g, &cmp, 1 << 16,
854+
memory_order_relaxed))
855+
return 1;
856+
} else if (cmp == 1) {
857+
if (!thr->in_ignored_lib)
858+
Acquire(thr, pc, (uptr)g);
859+
return 0;
860+
} else {
861+
internal_sched_yield();
862+
}
863+
}
864+
}
865+
866+
static void guard_release(ThreadState *thr, uptr pc, atomic_uint32_t *g) {
867+
if (!thr->in_ignored_lib)
868+
Release(thr, pc, (uptr)g);
869+
atomic_store(g, 1, memory_order_release);
870+
}
871+
847872
// __cxa_guard_acquire and friends need to be intercepted in a special way -
848873
// regular interceptors will break statically-linked libstdc++. Linux
849874
// interceptors are especially defined as weak functions (so that they don't
@@ -864,26 +889,12 @@ TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) {
864889
// Used in thread-safe function static initialization.
865890
STDCXX_INTERCEPTOR(int, __cxa_guard_acquire, atomic_uint32_t *g) {
866891
SCOPED_INTERCEPTOR_RAW(__cxa_guard_acquire, g);
867-
OnPotentiallyBlockingRegionBegin();
868-
auto on_exit = at_scope_exit(&OnPotentiallyBlockingRegionEnd);
869-
for (;;) {
870-
u32 cmp = atomic_load(g, memory_order_acquire);
871-
if (cmp == 0) {
872-
if (atomic_compare_exchange_strong(g, &cmp, 1<<16, memory_order_relaxed))
873-
return 1;
874-
} else if (cmp == 1) {
875-
Acquire(thr, pc, (uptr)g);
876-
return 0;
877-
} else {
878-
internal_sched_yield();
879-
}
880-
}
892+
return guard_acquire(thr, pc, g);
881893
}
882894

883895
STDCXX_INTERCEPTOR(void, __cxa_guard_release, atomic_uint32_t *g) {
884896
SCOPED_INTERCEPTOR_RAW(__cxa_guard_release, g);
885-
Release(thr, pc, (uptr)g);
886-
atomic_store(g, 1, memory_order_release);
897+
guard_release(thr, pc, g);
887898
}
888899

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

1483-
u32 v = atomic_load(a, memory_order_acquire);
1484-
if (v == 0 && atomic_compare_exchange_strong(a, &v, 1,
1485-
memory_order_relaxed)) {
1494+
if (guard_acquire(thr, pc, a)) {
14861495
(*f)();
1487-
if (!thr->in_ignored_lib)
1488-
Release(thr, pc, (uptr)o);
1489-
atomic_store(a, 2, memory_order_release);
1490-
} else {
1491-
while (v != 2) {
1492-
internal_sched_yield();
1493-
v = atomic_load(a, memory_order_acquire);
1494-
}
1495-
if (!thr->in_ignored_lib)
1496-
Acquire(thr, pc, (uptr)o);
1496+
guard_release(thr, pc, a);
14971497
}
14981498
return 0;
14991499
}

0 commit comments

Comments
 (0)