summaryrefslogtreecommitdiff
path: root/libcxx/include/__threading_support
diff options
context:
space:
mode:
Diffstat (limited to 'libcxx/include/__threading_support')
-rw-r--r--libcxx/include/__threading_support113
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;