diff options
Diffstat (limited to 'libcxx/include/__threading_support')
-rw-r--r-- | libcxx/include/__threading_support | 113 |
1 files changed, 112 insertions, 1 deletions
diff --git a/libcxx/include/__threading_support b/libcxx/include/__threading_support index 026429f6a8ec..072c4c7bcc89 100644 --- a/libcxx/include/__threading_support +++ b/libcxx/include/__threading_support @@ -26,6 +26,12 @@ #if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) # include <pthread.h> # include <sched.h> +# ifdef __APPLE__ +# define _LIBCPP_NO_NATIVE_SEMAPHORES +# endif +# ifndef _LIBCPP_NO_NATIVE_SEMAPHORES +# include <semaphore.h> +# endif #elif defined(_LIBCPP_HAS_THREAD_API_C11) # include <threads.h> #endif @@ -65,6 +71,12 @@ typedef pthread_mutex_t __libcpp_recursive_mutex_t; typedef pthread_cond_t __libcpp_condvar_t; #define _LIBCPP_CONDVAR_INITIALIZER PTHREAD_COND_INITIALIZER +#ifndef _LIBCPP_NO_NATIVE_SEMAPHORES +// Semaphore +typedef sem_t __libcpp_semaphore_t; +# define _LIBCPP_SEMAPHORE_MAX SEM_VALUE_MAX +#endif + // Execute once typedef pthread_once_t __libcpp_exec_once_flag; #define _LIBCPP_EXEC_ONCE_INITIALIZER PTHREAD_ONCE_INIT @@ -127,6 +139,9 @@ typedef void* __libcpp_recursive_mutex_t[5]; typedef void* __libcpp_condvar_t; #define _LIBCPP_CONDVAR_INITIALIZER 0 +// Semaphore +typedef void* __libcpp_semaphore_t; + // Execute Once typedef void* __libcpp_exec_once_flag; #define _LIBCPP_EXEC_ONCE_INITIALIZER 0 @@ -191,6 +206,26 @@ int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m, _LIBCPP_THREAD_ABI_VISIBILITY int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv); +#ifndef _LIBCPP_NO_NATIVE_SEMAPHORES + +// Semaphore +_LIBCPP_THREAD_ABI_VISIBILITY +bool __libcpp_semaphore_init(__libcpp_semaphore_t* __sem, int __init); + +_LIBCPP_THREAD_ABI_VISIBILITY +bool __libcpp_semaphore_destroy(__libcpp_semaphore_t* __sem); + +_LIBCPP_THREAD_ABI_VISIBILITY +bool __libcpp_semaphore_post(__libcpp_semaphore_t* __sem); + +_LIBCPP_THREAD_ABI_VISIBILITY +bool __libcpp_semaphore_wait(__libcpp_semaphore_t* __sem); + +_LIBCPP_THREAD_ABI_VISIBILITY +bool __libcpp_semaphore_wait_timed(__libcpp_semaphore_t* __sem, chrono::nanoseconds const& __ns); + +#endif // _LIBCPP_NO_NATIVE_SEMAPHORES + // Execute once _LIBCPP_THREAD_ABI_VISIBILITY int __libcpp_execute_once(__libcpp_exec_once_flag *flag, @@ -242,9 +277,52 @@ int __libcpp_tls_set(__libcpp_tls_key __key, void *__p); #endif // !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) +struct __libcpp_timed_backoff_policy { + _LIBCPP_THREAD_ABI_VISIBILITY + bool operator()(chrono::nanoseconds __elapsed) const; +}; + +inline _LIBCPP_INLINE_VISIBILITY +bool __libcpp_timed_backoff_policy::operator()(chrono::nanoseconds __elapsed) const +{ + if(__elapsed > chrono::milliseconds(128)) + __libcpp_thread_sleep_for(chrono::milliseconds(8)); + else if(__elapsed > chrono::microseconds(64)) + __libcpp_thread_sleep_for(__elapsed / 2); + else if(__elapsed > chrono::microseconds(4)) + __libcpp_thread_yield(); + else + ; // poll + return false; +} + +static _LIBCPP_CONSTEXPR const int __libcpp_polling_count = 64; + +template<class _Fn, class _BFn> +_LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY +bool __libcpp_thread_poll_with_backoff( + _Fn && __f, _BFn && __bf, chrono::nanoseconds __max_elapsed = chrono::nanoseconds::zero()) +{ + auto const __start = chrono::high_resolution_clock::now(); + for(int __count = 0;;) { + if(__f()) + return true; // _Fn completion means success + if(__count < __libcpp_polling_count) { + __count += 1; + continue; + } + chrono::nanoseconds const __elapsed = chrono::high_resolution_clock::now() - __start; + if(__max_elapsed != chrono::nanoseconds::zero() && __max_elapsed < __elapsed) + return false; // timeout failure + if(__bf(__elapsed)) + return false; // _BFn completion means failure + } +} + #if (!defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \ defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL)) + namespace __thread_detail { inline __libcpp_timespec_t __convert_to_timespec(const chrono::nanoseconds& __ns) @@ -364,6 +442,38 @@ int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv) return pthread_cond_destroy(__cv); } +#ifndef _LIBCPP_NO_NATIVE_SEMAPHORES + +// Semaphore +bool __libcpp_semaphore_init(__libcpp_semaphore_t* __sem, int __init) +{ + return sem_init(__sem, 0, __init) == 0; +} + +bool __libcpp_semaphore_destroy(__libcpp_semaphore_t* __sem) +{ + return sem_destroy(__sem) == 0; +} + +bool __libcpp_semaphore_post(__libcpp_semaphore_t* __sem) +{ + return sem_post(__sem) == 0; +} + +bool __libcpp_semaphore_wait(__libcpp_semaphore_t* __sem) +{ + return sem_wait(__sem) == 0; +} + +bool __libcpp_semaphore_wait_timed(__libcpp_semaphore_t* __sem, chrono::nanoseconds const& __ns) +{ + auto const __abs_time = chrono::system_clock::now().time_since_epoch() + __ns; + __libcpp_timespec_t __ts = __thread_detail::__convert_to_timespec(__abs_time); + return sem_timedwait(__sem, &__ts) == 0; +} + +#endif //_LIBCPP_NO_NATIVE_SEMAPHORES + // Execute once int __libcpp_execute_once(__libcpp_exec_once_flag *flag, void (*init_routine)()) { @@ -445,7 +555,7 @@ int __libcpp_tls_set(__libcpp_tls_key __key, void *__p) int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m) { - return mtx_init(__m, mtx_recursive) == thrd_success ? 0 : EINVAL; + return mtx_init(__m, mtx_plain | mtx_recursive) == thrd_success ? 0 : EINVAL; } int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m) @@ -600,6 +710,7 @@ int __libcpp_tls_set(__libcpp_tls_key __key, void *__p) #endif + #endif // !_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL || _LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL class _LIBCPP_TYPE_VIS thread; |