diff options
-rw-r--r-- | libcxxabi/src/cxa_guard_impl.h | 17 | ||||
-rw-r--r-- | libcxxabi/test/guard_test_basic.pass.cpp | 2 | ||||
-rw-r--r-- | libcxxabi/test/guard_threaded_test.pass.cpp | 47 |
3 files changed, 58 insertions, 8 deletions
diff --git a/libcxxabi/src/cxa_guard_impl.h b/libcxxabi/src/cxa_guard_impl.h index 8c31848625c..ea82d201331 100644 --- a/libcxxabi/src/cxa_guard_impl.h +++ b/libcxxabi/src/cxa_guard_impl.h @@ -70,6 +70,13 @@ # error "Either BUILDING_CXA_GUARD or TESTING_CXA_GUARD must be defined" #endif +#if __has_feature(thread_sanitizer) +extern "C" void __tsan_acquire(void*); +extern "C" void __tsan_release(void*); +#else +#define __tsan_acquire(addr) ((void)0) +#define __tsan_release(addr) ((void)0) +#endif namespace __cxxabiv1 { // Use an anonymous namespace to ensure that the tests and actual implementation @@ -116,7 +123,7 @@ constexpr uint32_t (*PlatformThreadID)() = nullptr; #endif -constexpr bool DoesPlatformSupportThreadID() { +constexpr bool PlatformSupportsThreadID() { #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wtautological-pointer-compare" @@ -265,7 +272,7 @@ struct InitByteGlobalMutex explicit InitByteGlobalMutex(uint32_t *g) : BaseT(g), has_thread_id_support(false) {} explicit InitByteGlobalMutex(uint64_t *g) - : BaseT(g), has_thread_id_support(DoesPlatformSupportThreadID()) {} + : BaseT(g), has_thread_id_support(PlatformSupportsThreadID()) {} public: AcquireResult acquire_init_byte() { @@ -358,9 +365,11 @@ private: void PlatformFutexWait(int* addr, int expect) { constexpr int WAIT = 0; syscall(SYS_futex, addr, WAIT, expect, 0); + __tsan_acquire(addr); } void PlatformFutexWake(int* addr) { constexpr int WAKE = 1; + __tsan_release(addr); syscall(SYS_futex, addr, WAKE, INT_MAX); } #else @@ -368,7 +377,7 @@ constexpr void (*PlatformFutexWait)(int*, int) = nullptr; constexpr void (*PlatformFutexWake)(int*) = nullptr; #endif -constexpr bool DoesPlatformSupportFutex() { +constexpr bool PlatformSupportsFutex() { #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wtautological-pointer-compare" @@ -539,7 +548,7 @@ constexpr Implementation CurrentImplementation = #endif static_assert(CurrentImplementation != Implementation::Futex - || DoesPlatformSupportFutex(), "Futex selected but not supported"); + || PlatformSupportsFutex(), "Futex selected but not supported"); using SelectedImplementation = SelectImplementation<CurrentImplementation>::type; diff --git a/libcxxabi/test/guard_test_basic.pass.cpp b/libcxxabi/test/guard_test_basic.pass.cpp index e04d694c845..a325dd0b732 100644 --- a/libcxxabi/test/guard_test_basic.pass.cpp +++ b/libcxxabi/test/guard_test_basic.pass.cpp @@ -129,7 +129,7 @@ int main() { #if defined(__APPLE__) || defined(__linux__) assert(PlatformThreadID); #endif - if (+PlatformThreadID) { + if (PlatformSupportsThreadID()) { assert(PlatformThreadID() != 0); assert(PlatformThreadID() == PlatformThreadID()); } diff --git a/libcxxabi/test/guard_threaded_test.pass.cpp b/libcxxabi/test/guard_threaded_test.pass.cpp index e38e132edfc..e46af564b70 100644 --- a/libcxxabi/test/guard_threaded_test.pass.cpp +++ b/libcxxabi/test/guard_threaded_test.pass.cpp @@ -356,14 +356,14 @@ void test_impl() { } } -int main() { +void test_all_impls() { using MutexImpl = SelectImplementation<Implementation::GlobalLock>::type; // Attempt to test the Futex based implementation if it's supported on the // target platform. using RealFutexImpl = SelectImplementation<Implementation::Futex>::type; using FutexImpl = typename std::conditional< - DoesPlatformSupportFutex(), + PlatformSupportsFutex(), RealFutexImpl, MutexImpl >::type; @@ -372,7 +372,48 @@ int main() { const int num_runs = 5; for (int i=0; i < num_runs; ++i) { test_impl<MutexImpl>(); - if (DoesPlatformSupportFutex()) + if (PlatformSupportsFutex()) test_impl<FutexImpl>(); } } + +// A dummy +template <bool Dummy = true> +void test_futex_syscall() { + if (!PlatformSupportsFutex()) + return; + int lock1 = 0; + int lock2 = 0; + int lock3 = 0; + std::thread waiter1([&]() { + int expect = 0; + PlatformFutexWait(&lock1, expect); + assert(lock1 == 1); + }); + std::thread waiter2([&]() { + int expect = 0; + PlatformFutexWait(&lock2, expect); + assert(lock2 == 2); + }); + std::thread waiter3([&]() { + int expect = 42; // not the value + PlatformFutexWait(&lock3, expect); // doesn't block + }); + std::thread waker([&]() { + lock1 = 1; + PlatformFutexWake(&lock1); + lock2 = 2; + PlatformFutexWake(&lock2); + }); + waiter1.join(); + waiter2.join(); + waiter3.join(); + waker.join(); +} + +int main() { + // Test each multi-threaded implementation with real threads. + test_all_impls(); + // Test the basic sanity of the futex syscall wrappers. + test_futex_syscall(); +} |