diff options
author | Asiri Rathnayake <asiri.rathnayake@arm.com> | 2016-10-13 15:05:19 +0000 |
---|---|---|
committer | Asiri Rathnayake <asiri.rathnayake@arm.com> | 2016-10-13 15:05:19 +0000 |
commit | 6d3ea6831d6fe30683d6b5078ad826fdedc2e946 (patch) | |
tree | 92f3fb6daa13e34459ba54f27f5bad8da3099793 /libcxxabi | |
parent | 85874a9360334ddb9619aca6344b8ee53296fa1e (diff) | |
download | bcm5719-llvm-6d3ea6831d6fe30683d6b5078ad826fdedc2e946.tar.gz bcm5719-llvm-6d3ea6831d6fe30683d6b5078ad826fdedc2e946.zip |
[libcxxabi] Refactor pthread usage into a separate API
This patch refactors all pthread uses of libc++abi into a separate API. This
is the first step towards supporting an externlly-threaded libc++abi library.
I've followed the conventions already used in the libc++ library for the same
purpose.
Patch from: Saleem Abdulrasool and Asiri Rathnayake
Reviewed by: compnerd, EricWF
Differential revisions:
https://reviews.llvm.org/D18482 (original)
https://reviews.llvm.org/D24864 (final)
llvm-svn: 284128
Diffstat (limited to 'libcxxabi')
-rw-r--r-- | libcxxabi/CMakeLists.txt | 1 | ||||
-rw-r--r-- | libcxxabi/src/config.h | 30 | ||||
-rw-r--r-- | libcxxabi/src/cxa_exception.cpp | 1 | ||||
-rw-r--r-- | libcxxabi/src/cxa_exception_storage.cpp | 24 | ||||
-rw-r--r-- | libcxxabi/src/cxa_guard.cpp | 36 | ||||
-rw-r--r-- | libcxxabi/src/cxa_thread_atexit.cpp | 25 | ||||
-rw-r--r-- | libcxxabi/src/fallback_malloc.cpp | 13 | ||||
-rw-r--r-- | libcxxabi/src/threading_support.h | 107 | ||||
-rw-r--r-- | libcxxabi/test/test_exception_storage.pass.cpp | 12 | ||||
-rw-r--r-- | libcxxabi/test/test_fallback_malloc.pass.cpp | 2 |
10 files changed, 192 insertions, 59 deletions
diff --git a/libcxxabi/CMakeLists.txt b/libcxxabi/CMakeLists.txt index e75c0b81bb4..73ec5c55750 100644 --- a/libcxxabi/CMakeLists.txt +++ b/libcxxabi/CMakeLists.txt @@ -340,6 +340,7 @@ endif() if (LIBCXXABI_HAS_PTHREAD_API) add_definitions(-D_LIBCPP_HAS_THREAD_API_PTHREAD) + add_definitions(-D_LIBCXXABI_USE_THREAD_API_PTHREAD) endif() if (MSVC) diff --git a/libcxxabi/src/config.h b/libcxxabi/src/config.h index 5d38d4d1465..d30c49b57ea 100644 --- a/libcxxabi/src/config.h +++ b/libcxxabi/src/config.h @@ -16,6 +16,36 @@ #include <unistd.h> +// Configure inline visibility attributes +#if defined(_WIN32) + #if defined(_MSC_VER) && !defined(__clang__) + // Using Microsoft Visual C++ compiler + #define _LIBCXXABI_INLINE_VISIBILITY __forceinline + #else + #if __has_attribute(__internal_linkage__) + #define _LIBCXXABI_INLINE_VISIBILITY __attribute__ ((__internal_linkage__, __always_inline__)) + #else + #define _LIBCXXABI_INLINE_VISIBILITY __attribute__ ((__always_inline__)) + #endif + #endif +#else + #if __has_attribute(__internal_linkage__) + #define _LIBCXXABI_INLINE_VISIBILITY __attribute__ ((__internal_linkage__, __always_inline__)) + #else + #define _LIBCXXABI_INLINE_VISIBILITY __attribute__ ((__visibility__("hidden"), __always_inline__)) + #endif +#endif + +// Try and deduce a threading api if one has not been explicitly set. +#if !defined(_LIBCXXABI_HAS_NO_THREADS) && \ + !defined(_LIBCXXABI_USE_THREAD_API_PTHREAD) + #if defined(_POSIX_THREADS) && _POSIX_THREADS >= 0 + #define _LIBCXXABI_USE_THREAD_API_PTHREAD + #else + #error "No thread API" + #endif +#endif + // Set this in the CXXFLAGS when you need it, because otherwise we'd have to // #if !defined(__linux__) && !defined(__APPLE__) && ... // and so-on for *every* platform. diff --git a/libcxxabi/src/cxa_exception.cpp b/libcxxabi/src/cxa_exception.cpp index 757b3d4558c..f84c0e84065 100644 --- a/libcxxabi/src/cxa_exception.cpp +++ b/libcxxabi/src/cxa_exception.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "config.h" +#include "threading_support.h" #include "cxxabi.h" #include <exception> // for std::terminate diff --git a/libcxxabi/src/cxa_exception_storage.cpp b/libcxxabi/src/cxa_exception_storage.cpp index ec69094c40c..d18eb0f84c2 100644 --- a/libcxxabi/src/cxa_exception_storage.cpp +++ b/libcxxabi/src/cxa_exception_storage.cpp @@ -14,6 +14,7 @@ #include "cxa_exception.hpp" #include "config.h" +#include "threading_support.h" #if defined(_LIBCXXABI_HAS_NO_THREADS) @@ -44,28 +45,27 @@ extern "C" { #else -#include <pthread.h> #include "abort_message.h" #include "fallback_malloc.h" -// In general, we treat all pthread errors as fatal. +// In general, we treat all threading errors as fatal. // We cannot call std::terminate() because that will in turn // call __cxa_get_globals() and cause infinite recursion. namespace __cxxabiv1 { namespace { - pthread_key_t key_; - pthread_once_t flag_ = PTHREAD_ONCE_INIT; + __libcxxabi_tls_key key_; + __libcxxabi_exec_once_flag flag_ = _LIBCXXABI_EXEC_ONCE_INITIALIZER; void destruct_ (void *p) { __free_with_fallback ( p ); - if ( 0 != ::pthread_setspecific ( key_, NULL ) ) + if ( 0 != __libcxxabi_tls_set ( key_, NULL ) ) abort_message("cannot zero out thread value for __cxa_get_globals()"); } void construct_ () { - if ( 0 != pthread_key_create ( &key_, destruct_ ) ) - abort_message("cannot create pthread key for __cxa_get_globals()"); + if ( 0 != __libcxxabi_tls_create ( &key_, destruct_ ) ) + abort_message("cannot create thread specific key for __cxa_get_globals()"); } } @@ -80,8 +80,8 @@ extern "C" { (__calloc_with_fallback (1, sizeof (__cxa_eh_globals))); if ( NULL == retVal ) abort_message("cannot allocate __cxa_eh_globals"); - if ( 0 != pthread_setspecific ( key_, retVal ) ) - abort_message("pthread_setspecific failure in __cxa_get_globals()"); + if ( 0 != __libcxxabi_tls_set ( key_, retVal ) ) + abort_message("__libcxxabi_tls_set failure in __cxa_get_globals()"); } return retVal; } @@ -92,10 +92,10 @@ extern "C" { // libc++abi. __cxa_eh_globals * __cxa_get_globals_fast () { // First time through, create the key. - if (0 != pthread_once(&flag_, construct_)) - abort_message("pthread_once failure in __cxa_get_globals_fast()"); + if (0 != __libcxxabi_execute_once(&flag_, construct_)) + abort_message("execute once failure in __cxa_get_globals_fast()"); // static int init = construct_(); - return static_cast<__cxa_eh_globals*>(::pthread_getspecific(key_)); + return static_cast<__cxa_eh_globals*>(__libcxxabi_tls_get(key_)); } } diff --git a/libcxxabi/src/cxa_guard.cpp b/libcxxabi/src/cxa_guard.cpp index 253d5d4ec5c..1c468ff5f8e 100644 --- a/libcxxabi/src/cxa_guard.cpp +++ b/libcxxabi/src/cxa_guard.cpp @@ -11,10 +11,8 @@ #include "abort_message.h" #include "config.h" +#include "threading_support.h" -#ifndef _LIBCXXABI_HAS_NO_THREADS -# include <pthread.h> -#endif #include <stdint.h> /* @@ -22,9 +20,9 @@ which will turn around and try to call __cxa_guard_acquire reentrantly. For this reason, the headers of this file are as restricted as possible. Previous implementations of this code for __APPLE__ have used - pthread_mutex_lock and the abort_message utility without problem. This - implementation also uses pthread_cond_wait which has tested to not be a - problem. + __libcxxabi_mutex_lock and the abort_message utility without problem. This + implementation also uses __libcxxabi_condvar_wait which has tested + to not be a problem. */ namespace __cxxabiv1 @@ -69,8 +67,8 @@ bool is_initialized(guard_type* guard_object) { #endif #ifndef _LIBCXXABI_HAS_NO_THREADS -pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t guard_cv = PTHREAD_COND_INITIALIZER; +__libcxxabi_mutex_t guard_mut = _LIBCXXABI_MUTEX_INITIALIZER; +__libcxxabi_condvar_t guard_cv = _LIBCXXABI_CONDVAR_INITIALIZER; #endif #if defined(__APPLE__) && !defined(__arm__) @@ -175,13 +173,13 @@ extern "C" #ifndef _LIBCXXABI_HAS_NO_THREADS _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) { char* initialized = (char*)guard_object; - if (pthread_mutex_lock(&guard_mut)) + if (__libcxxabi_mutex_lock(&guard_mut)) abort_message("__cxa_guard_acquire failed to acquire mutex"); int result = *initialized == 0; if (result) { #if defined(__APPLE__) && !defined(__arm__) - const lock_type id = pthread_mach_thread_np(pthread_self()); + const lock_type id = __libcxxabi_thread_get_port(); lock_type lock = get_lock(*guard_object); if (lock) { @@ -190,7 +188,7 @@ _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) { abort_message("__cxa_guard_acquire detected deadlock"); do { - if (pthread_cond_wait(&guard_cv, &guard_mut)) + if (__libcxxabi_condvar_wait(&guard_cv, &guard_mut)) abort_message("__cxa_guard_acquire condition variable wait failed"); lock = get_lock(*guard_object); } while (lock); @@ -202,36 +200,36 @@ _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) { set_lock(*guard_object, id); #else // !__APPLE__ || __arm__ while (get_lock(*guard_object)) - if (pthread_cond_wait(&guard_cv, &guard_mut)) + if (__libcxxabi_condvar_wait(&guard_cv, &guard_mut)) abort_message("__cxa_guard_acquire condition variable wait failed"); result = *initialized == 0; if (result) set_lock(*guard_object, true); #endif // !__APPLE__ || __arm__ } - if (pthread_mutex_unlock(&guard_mut)) + if (__libcxxabi_mutex_unlock(&guard_mut)) abort_message("__cxa_guard_acquire failed to release mutex"); return result; } _LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) { - if (pthread_mutex_lock(&guard_mut)) + if (__libcxxabi_mutex_lock(&guard_mut)) abort_message("__cxa_guard_release failed to acquire mutex"); *guard_object = 0; set_initialized(guard_object); - if (pthread_mutex_unlock(&guard_mut)) + if (__libcxxabi_mutex_unlock(&guard_mut)) abort_message("__cxa_guard_release failed to release mutex"); - if (pthread_cond_broadcast(&guard_cv)) + if (__libcxxabi_condvar_broadcast(&guard_cv)) abort_message("__cxa_guard_release failed to broadcast condition variable"); } _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) { - if (pthread_mutex_lock(&guard_mut)) + if (__libcxxabi_mutex_lock(&guard_mut)) abort_message("__cxa_guard_abort failed to acquire mutex"); *guard_object = 0; - if (pthread_mutex_unlock(&guard_mut)) + if (__libcxxabi_mutex_unlock(&guard_mut)) abort_message("__cxa_guard_abort failed to release mutex"); - if (pthread_cond_broadcast(&guard_cv)) + if (__libcxxabi_condvar_broadcast(&guard_cv)) abort_message("__cxa_guard_abort failed to broadcast condition variable"); } diff --git a/libcxxabi/src/cxa_thread_atexit.cpp b/libcxxabi/src/cxa_thread_atexit.cpp index dea5c21504b..933c9c7243c 100644 --- a/libcxxabi/src/cxa_thread_atexit.cpp +++ b/libcxxabi/src/cxa_thread_atexit.cpp @@ -9,8 +9,8 @@ #include "abort_message.h" #include "cxxabi.h" +#include "threading_support.h" #include <cstdlib> -#include <pthread.h> namespace __cxxabiv1 { @@ -39,9 +39,10 @@ namespace { // destructors of any objects with static storage duration. // // - thread_local destructors on non-main threads run on the first iteration - // through the pthread_key destructors. std::notify_all_at_thread_exit() - // and similar functions must be careful to wait until the second iteration - // to provide their intended ordering guarantees. + // through the __libcxxabi_tls_key destructors. + // std::notify_all_at_thread_exit() and similar functions must be careful to + // wait until the second iteration to provide their intended ordering + // guarantees. // // Another limitation, though one shared with ..._impl(), is that any // thread_locals that are first initialized after non-thread_local global @@ -65,7 +66,7 @@ namespace { // True if the destructors are currently scheduled to run on this thread __thread bool dtors_alive = false; // Used to trigger destructors on thread exit; value is ignored - pthread_key_t dtors_key; + __libcxxabi_tls_key dtors_key; void run_dtors(void*) { while (auto head = dtors) { @@ -79,16 +80,16 @@ namespace { struct DtorsManager { DtorsManager() { - // There is intentionally no matching pthread_key_delete call, as + // There is intentionally no matching __libcxxabi_tls_delete call, as // __cxa_thread_atexit() may be called arbitrarily late (for example, from // global destructors or atexit() handlers). - if (pthread_key_create(&dtors_key, run_dtors) != 0) { - abort_message("pthread_key_create() failed in __cxa_thread_atexit()"); + if (__libcxxabi_tls_create(&dtors_key, run_dtors) != 0) { + abort_message("__libcxxabi_tls_create() failed in __cxa_thread_atexit()"); } } ~DtorsManager() { - // pthread_key destructors do not run on threads that call exit() + // __libcxxabi_tls_key destructors do not run on threads that call exit() // (including when the main thread returns from main()), so we explicitly // call the destructor here. This runs at exit time (potentially earlier // if libc++abi is dlclose()'d). Any thread_locals initialized after this @@ -109,12 +110,12 @@ extern "C" { if (__cxa_thread_atexit_impl) { return __cxa_thread_atexit_impl(dtor, obj, dso_symbol); } else { - // Initialize the dtors pthread_key (uses __cxa_guard_*() for one-time - // initialization and __cxa_atexit() for destruction) + // Initialize the dtors __libcxxabi_tls_key (uses __cxa_guard_*() for + // one-time initialization and __cxa_atexit() for destruction) static DtorsManager manager; if (!dtors_alive) { - if (pthread_setspecific(dtors_key, &dtors_key) != 0) { + if (__libcxxabi_tls_set(dtors_key, &dtors_key) != 0) { return -1; } dtors_alive = true; diff --git a/libcxxabi/src/fallback_malloc.cpp b/libcxxabi/src/fallback_malloc.cpp index a436ed0ece7..5f52ece56f4 100644 --- a/libcxxabi/src/fallback_malloc.cpp +++ b/libcxxabi/src/fallback_malloc.cpp @@ -10,14 +10,11 @@ #include "fallback_malloc.h" #include "config.h" +#include "threading_support.h" #include <cstdlib> // for malloc, calloc, free #include <cstring> // for memset -#ifndef _LIBCXXABI_HAS_NO_THREADS -#include <pthread.h> // for mutexes -#endif - // A small, simple heap manager based (loosely) on // the startup heap manager from FreeBSD, optimized for space. // @@ -32,7 +29,7 @@ namespace { // When POSIX threads are not available, make the mutex operations a nop #ifndef _LIBCXXABI_HAS_NO_THREADS -static pthread_mutex_t heap_mutex = PTHREAD_MUTEX_INITIALIZER; +static __libcxxabi_mutex_t heap_mutex = _LIBCXXABI_MUTEX_INITIALIZER; #else static void * heap_mutex = 0; #endif @@ -40,8 +37,8 @@ static void * heap_mutex = 0; class mutexor { public: #ifndef _LIBCXXABI_HAS_NO_THREADS - mutexor ( pthread_mutex_t *m ) : mtx_(m) { pthread_mutex_lock ( mtx_ ); } - ~mutexor () { pthread_mutex_unlock ( mtx_ ); } + mutexor ( __libcxxabi_mutex_t *m ) : mtx_(m) { __libcxxabi_mutex_lock ( mtx_ ); } + ~mutexor () { __libcxxabi_mutex_unlock ( mtx_ ); } #else mutexor ( void * ) {} ~mutexor () {} @@ -50,7 +47,7 @@ private: mutexor ( const mutexor &rhs ); mutexor & operator = ( const mutexor &rhs ); #ifndef _LIBCXXABI_HAS_NO_THREADS - pthread_mutex_t *mtx_; + __libcxxabi_mutex_t *mtx_; #endif }; diff --git a/libcxxabi/src/threading_support.h b/libcxxabi/src/threading_support.h new file mode 100644 index 00000000000..78a225f8af4 --- /dev/null +++ b/libcxxabi/src/threading_support.h @@ -0,0 +1,107 @@ +//===------------------------ threading_support.h -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCXXABI_THREADING_SUPPORT_H +#define _LIBCXXABI_THREADING_SUPPORT_H + +#include "__cxxabi_config.h" +#include "config.h" + +#ifndef _LIBCXXABI_HAS_NO_THREADS + +#if defined(_LIBCXXABI_USE_THREAD_API_PTHREAD) +#include <pthread.h> + +#define _LIBCXXABI_THREAD_ABI_VISIBILITY inline _LIBCXXABI_INLINE_VISIBILITY + +// Mutex +typedef pthread_mutex_t __libcxxabi_mutex_t; +#define _LIBCXXABI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER + +_LIBCXXABI_THREAD_ABI_VISIBILITY +int __libcxxabi_mutex_lock(__libcxxabi_mutex_t *mutex) { + return pthread_mutex_lock(mutex); +} + +_LIBCXXABI_THREAD_ABI_VISIBILITY +int __libcxxabi_mutex_unlock(__libcxxabi_mutex_t *mutex) { + return pthread_mutex_unlock(mutex); +} + +// Condition variable +typedef pthread_cond_t __libcxxabi_condvar_t; +#define _LIBCXXABI_CONDVAR_INITIALIZER PTHREAD_COND_INITIALIZER + +_LIBCXXABI_THREAD_ABI_VISIBILITY +int __libcxxabi_condvar_wait(__libcxxabi_condvar_t *cv, + __libcxxabi_mutex_t *mutex) { + return pthread_cond_wait(cv, mutex); +} + +_LIBCXXABI_THREAD_ABI_VISIBILITY +int __libcxxabi_condvar_broadcast(__libcxxabi_condvar_t *cv) { + return pthread_cond_broadcast(cv); +} + +// Execute once +typedef pthread_once_t __libcxxabi_exec_once_flag; +#define _LIBCXXABI_EXEC_ONCE_INITIALIZER PTHREAD_ONCE_INIT + +_LIBCXXABI_THREAD_ABI_VISIBILITY +int __libcxxabi_execute_once(__libcxxabi_exec_once_flag *flag, + void (*init_routine)(void)) { + return pthread_once(flag, init_routine); +} + +// Thread id +#if defined(__APPLE__) && !defined(__arm__) +_LIBCXXABI_THREAD_ABI_VISIBILITY +mach_port_t __libcxxabi_thread_get_port() +{ + return pthread_mach_thread_np(pthread_self()); +} +#endif + +// Thread +typedef pthread_t __libcxxabi_thread_t; + +_LIBCXXABI_THREAD_ABI_VISIBILITY +int __libcxxabi_thread_create(__libcxxabi_thread_t* __t, + void* (*__func)(void*), void* __arg) +{ + return pthread_create(__t, 0, __func, __arg); +} + +_LIBCXXABI_THREAD_ABI_VISIBILITY +int __libcxxabi_thread_join(__libcxxabi_thread_t* __t) +{ + return pthread_join(*__t, 0); +} + +// TLS +typedef pthread_key_t __libcxxabi_tls_key; + +_LIBCXXABI_THREAD_ABI_VISIBILITY +int __libcxxabi_tls_create(__libcxxabi_tls_key *key, + void (*destructor)(void *)) { + return pthread_key_create(key, destructor); +} + +_LIBCXXABI_THREAD_ABI_VISIBILITY +void *__libcxxabi_tls_get(__libcxxabi_tls_key key) { + return pthread_getspecific(key); +} + +_LIBCXXABI_THREAD_ABI_VISIBILITY +int __libcxxabi_tls_set(__libcxxabi_tls_key key, void *value) { + return pthread_setspecific(key, value); +} +#endif // _LIBCXXABI_USE_THREAD_API_PTHREAD +#endif // !_LIBCXXABI_HAS_NO_THREADS +#endif // _LIBCXXABI_THREADING_SUPPORT_H diff --git a/libcxxabi/test/test_exception_storage.pass.cpp b/libcxxabi/test/test_exception_storage.pass.cpp index 90812469281..d5092274d91 100644 --- a/libcxxabi/test/test_exception_storage.pass.cpp +++ b/libcxxabi/test/test_exception_storage.pass.cpp @@ -12,9 +12,7 @@ #include <cstdlib> #include <algorithm> #include <iostream> -#ifndef _LIBCXXABI_HAS_NO_THREADS -# include <pthread.h> -#endif +#include "../src/threading_support.h" #include <unistd.h> #include "../src/cxa_exception.hpp" @@ -40,8 +38,8 @@ void *thread_code (void *parm) { #ifndef _LIBCXXABI_HAS_NO_THREADS #define NUMTHREADS 10 -size_t thread_globals [ NUMTHREADS ] = { 0 }; -pthread_t threads [ NUMTHREADS ]; +size_t thread_globals [ NUMTHREADS ] = { 0 }; +__libcxxabi_thread_t threads [ NUMTHREADS ]; #endif int main ( int argc, char *argv [] ) { @@ -50,9 +48,9 @@ int main ( int argc, char *argv [] ) { #ifndef _LIBCXXABI_HAS_NO_THREADS // Make the threads, let them run, and wait for them to finish for ( int i = 0; i < NUMTHREADS; ++i ) - pthread_create( threads + i, NULL, thread_code, (void *) (thread_globals + i)); + __libcxxabi_thread_create ( threads + i, thread_code, (void *) (thread_globals + i)); for ( int i = 0; i < NUMTHREADS; ++i ) - pthread_join ( threads [ i ], NULL ); + __libcxxabi_thread_join ( &threads [ i ] ); for ( int i = 0; i < NUMTHREADS; ++i ) if ( 0 == thread_globals [ i ] ) { diff --git a/libcxxabi/test/test_fallback_malloc.pass.cpp b/libcxxabi/test/test_fallback_malloc.pass.cpp index 474e0b3b336..250a7389186 100644 --- a/libcxxabi/test/test_fallback_malloc.pass.cpp +++ b/libcxxabi/test/test_fallback_malloc.pass.cpp @@ -10,7 +10,7 @@ #include <iostream> #include <deque> -#include <pthread.h> +#include "../src/threading_support.h" typedef std::deque<void *> container; |