Index: libcxx/include/__config =================================================================== --- libcxx/include/__config +++ libcxx/include/__config @@ -1111,7 +1111,6 @@ !defined(_LIBCPP_HAS_THREAD_API_WIN32) && \ !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) # if defined(__FreeBSD__) || \ - defined(__Fuchsia__) || \ defined(__wasi__) || \ defined(__NetBSD__) || \ defined(__linux__) || \ @@ -1121,6 +1120,8 @@ defined(__sun__) || \ (defined(__MINGW32__) && __has_include()) # define _LIBCPP_HAS_THREAD_API_PTHREAD +# elif defined(__Fuchsia__) +# define _LIBCPP_HAS_THREAD_API_C11 # elif defined(_LIBCPP_WIN32API) # define _LIBCPP_HAS_THREAD_API_WIN32 # else @@ -1172,6 +1173,7 @@ // TODO(EricWF): Enable this optimization on Bionic after speaking to their // respective stakeholders. #if (defined(_LIBCPP_HAS_THREAD_API_PTHREAD) && defined(__GLIBC__)) \ + || (defined(_LIBCPP_HAS_THREAD_API_C11) && defined(__Fuchsia__)) \ || defined(_LIBCPP_HAS_THREAD_API_WIN32) # define _LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION #endif @@ -1184,7 +1186,8 @@ // // TODO(EricWF): This is potentially true for some pthread implementations // as well. -#if defined(_LIBCPP_HAS_THREAD_API_WIN32) +#if (defined(_LIBCPP_HAS_THREAD_API_C11) && defined(__Fuchsia__)) || \ + defined(_LIBCPP_HAS_THREAD_API_WIN32) # define _LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION #endif Index: libcxx/include/__threading_support =================================================================== --- libcxx/include/__threading_support +++ libcxx/include/__threading_support @@ -26,6 +26,8 @@ #if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) # include # include +#elif defined(_LIBCPP_HAS_THREAD_API_C11) +# include #endif #if defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \ @@ -78,6 +80,35 @@ // Thread Local Storage typedef pthread_key_t __libcpp_tls_key; +#define _LIBCPP_TLS_DESTRUCTOR_CC +#elif defined(_LIBCPP_HAS_THREAD_API_C11) +// Mutex +typedef mtx_t __libcpp_mutex_t; +// mtx_t is a struct so using {} for initialization is valid. +#define _LIBCPP_MUTEX_INITIALIZER {} + +typedef mtx_t __libcpp_recursive_mutex_t; + +// Condition Variable +typedef cnd_t __libcpp_condvar_t; +// cnd_t is a struct so using {} for initialization is valid. +#define _LIBCPP_CONDVAR_INITIALIZER {} + +// Execute once +typedef once_flag __libcpp_exec_once_flag; +#define _LIBCPP_EXEC_ONCE_INITIALIZER ONCE_FLAG_INIT + +// Thread id +typedef thrd_t __libcpp_thread_id; + +// Thread +#define _LIBCPP_NULL_THREAD 0U + +typedef thrd_t __libcpp_thread_t; + +// Thread Local Storage +typedef tss_t __libcpp_tls_key; + #define _LIBCPP_TLS_DESTRUCTOR_CC #elif !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) // Mutex @@ -212,8 +243,35 @@ #endif // !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) #if (!defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \ - defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL)) && \ - defined(_LIBCPP_HAS_THREAD_API_PTHREAD) + defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL)) + +namespace __thread_detail { + +inline __libcpp_timespec_t __convert_to_timespec(const chrono::nanoseconds& __ns) +{ + using namespace chrono; + seconds __s = duration_cast(__ns); + __libcpp_timespec_t __ts; + typedef decltype(__ts.tv_sec) __ts_sec; + const __ts_sec __ts_sec_max = numeric_limits<__ts_sec>::max(); + + if (__s.count() < __ts_sec_max) + { + __ts.tv_sec = static_cast<__ts_sec>(__s.count()); + __ts.tv_nsec = static_cast((__ns - __s).count()); + } + else + { + __ts.tv_sec = __ts_sec_max; + __ts.tv_nsec = 999999999; // (10^9 - 1) + } + + return __ts; +} + +} + +#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m) { @@ -363,23 +421,7 @@ void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns) { - using namespace chrono; - seconds __s = duration_cast(__ns); - __libcpp_timespec_t __ts; - typedef decltype(__ts.tv_sec) ts_sec; - _LIBCPP_CONSTEXPR ts_sec __ts_sec_max = numeric_limits::max(); - - if (__s.count() < __ts_sec_max) - { - __ts.tv_sec = static_cast(__s.count()); - __ts.tv_nsec = static_cast((__ns - __s).count()); - } - else - { - __ts.tv_sec = __ts_sec_max; - __ts.tv_nsec = 999999999; // (10^9 - 1) - } - + __libcpp_timespec_t __ts = __thread_detail::__convert_to_timespec(__ns); while (nanosleep(&__ts, &__ts) == -1 && errno == EINTR); } @@ -399,6 +441,165 @@ return pthread_setspecific(__key, __p); } +#elif defined(_LIBCPP_HAS_THREAD_API_C11) + +int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m) +{ + return mtx_init(__m, mtx_recursive) == thrd_success ? 0 : EINVAL; +} + +int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t *__m) +{ + return mtx_lock(__m) == thrd_success ? 0 : EINVAL; +} + +bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t *__m) +{ + return mtx_trylock(__m) == thrd_success; +} + +int __libcpp_recursive_mutex_unlock(__libcpp_mutex_t *__m) +{ + return mtx_unlock(__m) == thrd_success ? 0 : EINVAL; +} + +int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t *__m) +{ + mtx_destroy(__m); + return 0; +} + +int __libcpp_mutex_lock(__libcpp_mutex_t *__m) +{ + return mtx_lock(__m) == thrd_success ? 0 : EINVAL; +} + +bool __libcpp_mutex_trylock(__libcpp_mutex_t *__m) +{ + return mtx_trylock(__m) == thrd_success; +} + +int __libcpp_mutex_unlock(__libcpp_mutex_t *__m) +{ + return mtx_unlock(__m) == thrd_success ? 0 : EINVAL; +} + +int __libcpp_mutex_destroy(__libcpp_mutex_t *__m) +{ + mtx_destroy(__m); + return 0; +} + +// Condition Variable +int __libcpp_condvar_signal(__libcpp_condvar_t *__cv) +{ + return cnd_signal(__cv) == thrd_success ? 0 : EINVAL; +} + +int __libcpp_condvar_broadcast(__libcpp_condvar_t *__cv) +{ + return cnd_broadcast(__cv) == thrd_success ? 0 : EINVAL; +} + +int __libcpp_condvar_wait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m) +{ + return cnd_wait(__cv, __m) == thrd_success ? 0 : EINVAL; +} + +int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m, + timespec *__ts) +{ + int __ec = cnd_timedwait(__cv, __m, __ts); + return __ec == thrd_timedout ? ETIMEDOUT : __ec; +} + +int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv) +{ + cnd_destroy(__cv); + return 0; +} + +// Execute once +int __libcpp_execute_once(__libcpp_exec_once_flag *flag, + void (*init_routine)(void)) { + ::call_once(flag, init_routine); + return 0; +} + +// Thread id +// Returns non-zero if the thread ids are equal, otherwise 0 +bool __libcpp_thread_id_equal(__libcpp_thread_id t1, __libcpp_thread_id t2) +{ + return thrd_equal(t1, t2) != 0; +} + +// Returns non-zero if t1 < t2, otherwise 0 +bool __libcpp_thread_id_less(__libcpp_thread_id t1, __libcpp_thread_id t2) +{ + return t1 < t2; +} + +// Thread +bool __libcpp_thread_isnull(const __libcpp_thread_t *__t) { + return *__t == 0; +} + +int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *), + void *__arg) +{ + int __ec = thrd_create(__t, reinterpret_cast(__func), __arg); + return __ec == thrd_nomem ? ENOMEM : __ec; +} + +__libcpp_thread_id __libcpp_thread_get_current_id() +{ + return thrd_current(); +} + +__libcpp_thread_id __libcpp_thread_get_id(const __libcpp_thread_t *__t) +{ + return *__t; +} + +int __libcpp_thread_join(__libcpp_thread_t *__t) +{ + return thrd_join(*__t, nullptr) == thrd_success ? 0 : EINVAL; +} + +int __libcpp_thread_detach(__libcpp_thread_t *__t) +{ + return thrd_detach(*__t) == thrd_success ? 0 : EINVAL; +} + +void __libcpp_thread_yield() +{ + thrd_yield(); +} + +void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns) +{ + __libcpp_timespec_t __ts = __thread_detail::__convert_to_timespec(__ns); + thrd_sleep(&__ts, nullptr); +} + +// Thread local storage +int __libcpp_tls_create(__libcpp_tls_key *__key, void (*__at_exit)(void *)) +{ + return tss_create(__key, __at_exit) == thrd_success ? 0 : EINVAL; +} + +void *__libcpp_tls_get(__libcpp_tls_key __key) +{ + return tss_get(__key); +} + +int __libcpp_tls_set(__libcpp_tls_key __key, void *__p) +{ + return tss_set(__key, __p) == thrd_success ? 0 : EINVAL; +} + +#endif + #endif // !_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL || _LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL class _LIBCPP_TYPE_VIS thread;