| //===-- Shared pthread condition variable helpers ---------------*- C++ -*-===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_UTILS_H | |
| #define LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_UTILS_H | |
| #include "hdr/errno_macros.h" // EINVAL, ETIMEDOUT | |
| #include "hdr/time_macros.h" // CLOCK_MONOTONIC, CLOCK_REALTIME | |
| #include "include/llvm-libc-types/clockid_t.h" | |
| #include "include/llvm-libc-types/pthread_cond_t.h" | |
| #include "include/llvm-libc-types/pthread_mutex_t.h" | |
| #include "include/llvm-libc-types/struct_timespec.h" | |
| #include "src/__support/CPP/optional.h" | |
| #include "src/__support/common.h" | |
| #include "src/__support/macros/config.h" | |
| #include "src/__support/macros/null_check.h" | |
| #include "src/__support/macros/optimization.h" | |
| #include "src/__support/threads/CndVar.h" | |
| #include "src/__support/threads/mutex.h" | |
| #include "src/__support/time/abs_timeout.h" | |
| namespace LIBC_NAMESPACE_DECL { | |
| namespace pthread_cond_utils { | |
| static_assert( | |
| sizeof(CndVar) == sizeof(pthread_cond_t) && | |
| alignof(CndVar) == alignof(pthread_cond_t), | |
| "The public pthread_cond_t type must be of the same size and alignment " | |
| "as the internal condition variable type."); | |
| LIBC_INLINE CndVar *to_cndvar(pthread_cond_t *cond) { | |
| LIBC_CRASH_ON_NULLPTR(cond); | |
| // TODO: use cpp:start_lifetime_as once | |
| // https://github.com/llvm/llvm-project/pull/193326 is merged | |
| return reinterpret_cast<CndVar *>(cond); | |
| } | |
| LIBC_INLINE Mutex *to_mutex(pthread_mutex_t *mutex) { | |
| LIBC_CRASH_ON_NULLPTR(mutex); | |
| // TODO: use cpp:start_lifetime_as once | |
| // https://github.com/llvm/llvm-project/pull/193326 is merged | |
| Mutex *m = reinterpret_cast<Mutex *>(mutex); | |
| LIBC_ASSERT(!m->is_robust() && "Robust mutex not supported yet"); | |
| return m; | |
| } | |
| LIBC_INLINE bool is_supported_clock(clockid_t clock_id) { | |
| return clock_id == CLOCK_MONOTONIC || clock_id == CLOCK_REALTIME; | |
| } | |
| LIBC_INLINE bool is_realtime_clock(clockid_t clock_id) { | |
| return clock_id == CLOCK_REALTIME; | |
| } | |
| LIBC_INLINE int wait(CndVar *cond, Mutex *mutex, | |
| cpp::optional<CndVar::Timeout> timeout) { | |
| switch (cond->wait(mutex, timeout)) { | |
| case CndVarResult::Success: | |
| return 0; | |
| case CndVarResult::Timeout: | |
| return ETIMEDOUT; | |
| case CndVarResult::MutexError: | |
| return EINVAL; | |
| } | |
| __builtin_unreachable(); | |
| } | |
| LIBC_INLINE int timed_wait(CndVar *cond, Mutex *mutex, | |
| const struct timespec *abstime, bool is_realtime) { | |
| LIBC_CRASH_ON_NULLPTR(abstime); | |
| auto timeout = | |
| internal::AbsTimeout::from_timespec(*abstime, /*realtime=*/is_realtime); | |
| if (LIBC_LIKELY(timeout.has_value())) | |
| return wait(cond, mutex, timeout.value()); | |
| switch (timeout.error()) { | |
| case internal::AbsTimeout::Error::Invalid: | |
| return EINVAL; | |
| case internal::AbsTimeout::Error::BeforeEpoch: | |
| return ETIMEDOUT; | |
| } | |
| __builtin_unreachable(); | |
| } | |
| } // namespace pthread_cond_utils | |
| } // namespace LIBC_NAMESPACE_DECL | |
| #endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_COND_UTILS_H |