[compiler-rt][builtins] Add opt-in pthread_mutex_t locks to libatomic (#95326)

When an uninstrumented libatomic is used with a TSan instrumented
memcpy, TSan may report a data race in circumstances where writes are
arguably safe.

This occurs because __atomic_compare_exchange won't be instrumented in
an uninstrumented libatomic, so TSan doesn't know that the subsequent
memcpy is race-free.

On the other hand, pthread_mutex_(un)lock will be intercepted by TSan,
meaning an uninstrumented libatomic will not report this false-positive.

pthread_mutexes also may try a number of different strategies to acquire
the lock, which may bound the amount of time a thread has to wait for a
lock during contention.

While pthread_mutex_lock has a larger overhead (due to the function call
and some dispatching), a dispatch to libatomic already predicates a lack
of performance guarantees.
This commit is contained in:
Logikable 2024-06-13 10:03:15 -07:00 committed by GitHub
parent a239343521
commit 6499c5d70c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 20 additions and 2 deletions

View File

@ -237,6 +237,14 @@ if(NOT FUCHSIA AND NOT COMPILER_RT_BAREMETAL_BUILD)
) )
endif() endif()
option(COMPILER_RT_LIBATOMIC_USE_PTHREAD
"Whether libatomic should use pthreads if available."
Off)
if(COMPILER_RT_LIBATOMIC_USE_PTHREAD)
add_compile_definitions(_LIBATOMIC_USE_PTHREAD)
endif()
if(COMPILER_RT_HAS_ATOMIC_KEYWORD AND NOT COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN) if(COMPILER_RT_HAS_ATOMIC_KEYWORD AND NOT COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN)
set(GENERIC_SOURCES set(GENERIC_SOURCES
${GENERIC_SOURCES} ${GENERIC_SOURCES}

View File

@ -12,7 +12,7 @@
// //
// 1) This code must work with C programs that do not link to anything // 1) This code must work with C programs that do not link to anything
// (including pthreads) and so it should not depend on any pthread // (including pthreads) and so it should not depend on any pthread
// functions. // functions. If the user wishes to opt into using pthreads, they may do so.
// 2) Atomic operations, rather than explicit mutexes, are most commonly used // 2) Atomic operations, rather than explicit mutexes, are most commonly used
// on code where contended operations are rate. // on code where contended operations are rate.
// //
@ -56,7 +56,17 @@ static const long SPINLOCK_MASK = SPINLOCK_COUNT - 1;
// defined. Each platform should define the Lock type, and corresponding // defined. Each platform should define the Lock type, and corresponding
// lock() and unlock() functions. // lock() and unlock() functions.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#if defined(__FreeBSD__) || defined(__DragonFly__) #if defined(_LIBATOMIC_USE_PTHREAD)
#include <pthread.h>
typedef pthread_mutex_t Lock;
/// Unlock a lock. This is a release operation.
__inline static void unlock(Lock *l) { pthread_mutex_unlock(l); }
/// Locks a lock.
__inline static void lock(Lock *l) { pthread_mutex_lock(l); }
/// locks for atomic operations
static Lock locks[SPINLOCK_COUNT];
#elif defined(__FreeBSD__) || defined(__DragonFly__)
#include <errno.h> #include <errno.h>
// clang-format off // clang-format off
#include <sys/types.h> #include <sys/types.h>