4#define _POSIX_C_SOURCE 200809L
6#define _DARWIN_C_SOURCE
34#define POSIX_PERIOD_NS_PER_MS 1000000L
35#define POSIX_PERIOD_NS_PER_S 1000000000L
38#define POSIX_PERIOD_WAIT_FAILED (-1)
42#ifndef RTE_POSIX_PERIOD_WAKE_LOCK_TIMEOUT_MS
43#define RTE_POSIX_PERIOD_WAKE_LOCK_TIMEOUT_MS 50U
51static bool time_left_ns(
const struct timespec *deadline, int64_t *out_ns);
53static rte_status_t
wait_to_deadline(
const struct timespec *deadline,
const volatile sig_atomic_t *should_stop);
54static rte_status_t
wait_locked(
const struct timespec *deadline,
const volatile sig_atomic_t *should_stop,
63static pthread_cond_t s_wake_cond;
64static bool s_wake_ready =
false;
72 rte_status_t status = RTE_STATUS_INVALID_PARAM;
74 if (out_deadline != NULL)
79 if (clock_gettime(CLOCK_MONOTONIC, &now) == 0)
82 status = RTE_STATUS_OK;
86 status = RTE_STATUS_INTERNAL_ERROR;
96 rte_duration_ms_t whole_s = period_ms / 1000U;
97 rte_duration_ms_t rest_ms = period_ms % 1000U;
99 deadline->tv_sec += (time_t)whole_s;
101 if (deadline->tv_nsec >= POSIX_PERIOD_NS_PER_S)
103 deadline->tv_sec += 1;
104 deadline->tv_nsec -= POSIX_PERIOD_NS_PER_S;
111 rte_status_t status = RTE_STATUS_INVALID_PARAM;
113 if ((deadline != NULL) && (should_stop != NULL))
121 status = RTE_STATUS_INTERNAL_ERROR;
129 static pthread_once_t wake_once = PTHREAD_ONCE_INIT;
134 ready = s_wake_ready;
141 if (should_stop != NULL)
156 (void)pthread_cond_broadcast(&s_wake_cond);
169 pthread_mutexattr_t mutex_attr;
170 pthread_condattr_t cond_attr;
171 bool mutex_created =
false;
172 bool created =
false;
176 if (pthread_mutexattr_init(&mutex_attr) == 0)
178 if (pthread_mutexattr_setprotocol(&mutex_attr, PTHREAD_PRIO_INHERIT) == 0)
180 mutex_created = (pthread_mutex_init(&
s_wake_lock, &mutex_attr) == 0);
182 (void)pthread_mutexattr_destroy(&mutex_attr);
187 if (pthread_condattr_init(&cond_attr) == 0)
191 created = (pthread_cond_init(&s_wake_cond, &cond_attr) == 0);
193 (void)pthread_condattr_destroy(&cond_attr);
201 s_wake_ready = created;
206 POSIX_OSA_REPORT_RT_ATTRIBUTE(
"period wake object refused - timer/task create failed");
210#if defined(__APPLE__)
223 return (pthread_condattr_setclock(attr, CLOCK_MONOTONIC) == 0);
229static bool time_left_ns(
const struct timespec *deadline, int64_t *out_ns)
234 if (clock_gettime(CLOCK_MONOTONIC, &now) == 0)
236 *out_ns = (((int64_t)deadline->tv_sec - (int64_t)now.tv_sec) * POSIX_PERIOD_NS_PER_S) +
237 ((int64_t)deadline->tv_nsec - (int64_t)now.tv_nsec);
248 rte_duration_ms_t result = (rte_duration_ms_t)UINT32_MAX;
250 if (ms < (int64_t)UINT32_MAX)
252 result = (rte_duration_ms_t)ms;
258static rte_status_t
wait_to_deadline(
const struct timespec *deadline,
const volatile sig_atomic_t *should_stop)
260 rte_status_t status = RTE_STATUS_OK;
261 bool waiting = (*should_stop == 0);
265 int64_t remaining_ns = 0;
269 status = RTE_STATUS_INTERNAL_ERROR;
272 else if (remaining_ns <= 0)
280 if (lock_status == RTE_STATUS_OK)
282 status =
wait_locked(deadline, should_stop, &waiting);
284 else if (lock_status == RTE_STATUS_TIMEOUT)
288 waiting = (*should_stop == 0);
292 status = RTE_STATUS_INTERNAL_ERROR;
303static rte_status_t
wait_locked(
const struct timespec *deadline,
const volatile sig_atomic_t *should_stop,
306 rte_status_t status = RTE_STATUS_OK;
310 if (*should_stop == 0)
314 *out_waiting = (*should_stop == 0);
317 rc = POSIX_PERIOD_WAIT_FAILED;
319 if ((rc != 0) && (rc != ETIMEDOUT))
321 status = RTE_STATUS_INTERNAL_ERROR;
322 *out_waiting =
false;
327#if defined(__APPLE__)
335 int64_t remaining_ns = 0;
339 rc = POSIX_PERIOD_WAIT_FAILED;
341 else if (remaining_ns > 0)
343 struct timespec relative;
344 int64_t whole_s = remaining_ns / POSIX_PERIOD_NS_PER_S;
345 int64_t rest_ns = remaining_ns % POSIX_PERIOD_NS_PER_S;
347 relative.tv_sec = (time_t)whole_s;
348 relative.tv_nsec = (long)rest_ns;
349 rc = pthread_cond_timedwait_relative_np(&s_wake_cond, &
s_wake_lock, &relative);
362 return pthread_cond_timedwait(&s_wake_cond, &
s_wake_lock, deadline);
rte_status_t posix_osa_lock_bounded(pthread_mutex_t *mutex, rte_duration_ms_t timeout_ms)
Waits at most timeout_ms for a pthread mutex.
Private helper: a bounded wait for a pthread mutex (OSA rule R2: every wait bounded).
rte_status_t posix_period_init(struct timespec *out_deadline)
Starts a period: reads CLOCK_MONOTONIC into the deadline.
static rte_status_t wait_locked(const struct timespec *deadline, const volatile sig_atomic_t *should_stop, bool *out_waiting)
static pthread_mutex_t s_wake_lock
static int wait_for_wake(const struct timespec *deadline)
static rte_status_t wait_to_deadline(const struct timespec *deadline, const volatile sig_atomic_t *should_stop)
void posix_period_wake_all(volatile sig_atomic_t *should_stop)
Requests a stop of a periodic thread and wakes it from its wait.
bool posix_period_wake_ready(void)
Creates the process-wide wake object on the first call; true once it exists.
static bool time_left_ns(const struct timespec *deadline, int64_t *out_ns)
rte_status_t posix_period_sleep_until(const struct timespec *deadline, const volatile sig_atomic_t *should_stop)
Waits until the absolute CLOCK_MONOTONIC deadline, or until a stop is requested.
static rte_duration_ms_t ns_to_ms_rounded_up(int64_t ns)
static bool set_wake_clock(pthread_condattr_t *attr)
#define POSIX_PERIOD_NS_PER_MS
void posix_period_advance(struct timespec *deadline, rte_duration_ms_t period_ms)
Moves the deadline one period later, keeping tv_nsec in [0, 1 s).
static void create_wake_object(void)
Private helper: pacing of a periodic thread by an absolute CLOCK_MONOTONIC deadline (OSA rule R3),...
Private helper: reports a real-time attribute this OSAdapter could not apply (OSA rules R1/R2/R6).