blob: 1750f822d731294cc0df9aae7437539755ac234a [file]
//===-- 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