diff --git a/libcxxabi/src/cxa_exception_storage.cpp b/libcxxabi/src/cxa_exception_storage.cpp --- a/libcxxabi/src/cxa_exception_storage.cpp +++ b/libcxxabi/src/cxa_exception_storage.cpp @@ -92,10 +92,16 @@ // to the Itanium ABI and is taken advantage of in several places in // libc++abi. __cxa_eh_globals *__cxa_get_globals_fast() { - // First time through, create the key. - if (0 != std::__libcpp_execute_once(&flag_, construct_)) - abort_message("execute once failure in __cxa_get_globals_fast()"); - return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_)); + // If threads are disabled at runtime, revert to single-threaded implementation. + static const bool threadsEnabled = std::__libcpp_are_threads_enabled(); + if (!threadsEnabled) { + static __cxa_eh_globals eh_globals; + return &eh_globals; + } + // First time through, create the key. + if (0 != std::__libcpp_execute_once(&flag_, construct_)) + abort_message("execute once failure in __cxa_get_globals_fast()"); + return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_)); } } // extern "C" } // namespace __cxxabiv1 diff --git a/libcxxabi/test/test_exception_storage.pass.cpp b/libcxxabi/test/test_exception_storage.pass.cpp --- a/libcxxabi/test/test_exception_storage.pass.cpp +++ b/libcxxabi/test/test_exception_storage.pass.cpp @@ -42,33 +42,40 @@ #endif int main() { -#ifndef _LIBCXXABI_HAS_NO_THREADS -// Make the threads, let them run, and wait for them to finish - for ( int i = 0; i < NUMTHREADS; ++i ) - std::__libcpp_thread_create ( threads + i, thread_code, (void *) (thread_globals + i)); - for ( int i = 0; i < NUMTHREADS; ++i ) - std::__libcpp_thread_join ( &threads [ i ] ); +#ifdef _LIBCXXABI_HAS_NO_THREADS + size_t thread_globals; + thread_code(&thread_globals); + // Check that __cxa_get_globals() is not NULL. + return (thread_globals == 0) ? 1 : 0; +#else // !_LIBCXXABI_HAS_NO_THREADS + // If threads are disabled at runtime, revert to single-threaded test. + if (!std::__libcpp_are_threads_enabled()) { + thread_code((void*)thread_globals); + // Check that __cxa_get_globals() is not NULL. + return (thread_globals[0] == 0) ? 1 : 0; + } - int retVal = 0; - for ( int i = 0; i < NUMTHREADS; ++i ) { - if ( 0 == thread_globals [ i ] ) { - std::printf("Thread #%d had a zero global\n", i); - retVal = 1; - } + // Make the threads, let them run, and wait for them to finish + for (int i = 0; i < NUMTHREADS; ++i) + std::__libcpp_thread_create(threads + i, thread_code, (void*)(thread_globals + i)); + for (int i = 0; i < NUMTHREADS; ++i) + std::__libcpp_thread_join(&threads[i]); + + int retVal = 0; + for (int i = 0; i < NUMTHREADS; ++i) { + if (0 == thread_globals[i]) { + std::printf("Thread #%d had a zero global\n", i); + retVal = 1; } + } - std::sort ( thread_globals, thread_globals + NUMTHREADS ); - for ( int i = 1; i < NUMTHREADS; ++i ) { - if ( thread_globals [ i - 1 ] == thread_globals [ i ] ) { - std::printf("Duplicate thread globals (%d and %d)\n", i-1, i); - retVal = 2; - } + std::sort(thread_globals, thread_globals + NUMTHREADS); + for (int i = 1; i < NUMTHREADS; ++i) { + if (thread_globals[i - 1] == thread_globals[i]) { + std::printf("Duplicate thread globals (%d and %d)\n", i - 1, i); + retVal = 2; } - return retVal; -#else // _LIBCXXABI_HAS_NO_THREADS - size_t thread_globals; - thread_code(&thread_globals); - // Check that __cxa_get_globals() is not NULL. - return (thread_globals == 0) ? 1 : 0; + } + return retVal; #endif // !_LIBCXXABI_HAS_NO_THREADS }