1#define _POSIX_C_SOURCE 200809L
22#include "safeapi/oal/memory/sapi_mem_util.h"
31 sapi_timer_config_t config;
32 volatile sig_atomic_t running;
33 volatile sig_atomic_t should_stop;
34 sapi_timer_handle_t self_handle;
40typedef char posix_timer_storage_fits_[(
sizeof(
posix_timer_state_t) <=
sizeof(sapi_timer_storage_t)) ? 1 : -1];
43#if !defined(__linux__)
44static void ms_to_timespec(sapi_duration_ms_t ms,
struct timespec *out_ts);
46static void *timer_thread_main(
void *arg);
47static sapi_status_t backend_create(sapi_timer_storage_t *storage,
const sapi_timer_config_t *config,
48 sapi_timer_handle_t *out_handle);
49static sapi_status_t backend_stop(sapi_timer_handle_t handle);
50static sapi_status_t backend_start(sapi_timer_handle_t handle);
51static sapi_status_t backend_destroy(sapi_timer_handle_t handle);
52static sapi_status_t backend_now(sapi_timestamp_ms_t *out_now_ms);
56 backend_destroy, backend_now };
70#if !defined(__linux__)
71static void ms_to_timespec(sapi_duration_ms_t ms,
struct timespec *out_ts)
73 out_ts->tv_sec = (time_t)(ms / 1000U);
74 out_ts->tv_nsec = (long)((ms % 1000U) * 1000000L);
79static void timespec_add_ms(
struct timespec *ts, sapi_duration_ms_t ms)
81 ts->tv_sec += (time_t)(ms / 1000U);
82 ts->tv_nsec += (long)((ms % 1000U) * 1000000L);
83 if (ts->tv_nsec >= 1000000000L)
86 ts->tv_nsec -= 1000000000L;
91static void *timer_thread_main(
void *arg)
95 struct timespec next_wake_ts;
97 if (clock_gettime(CLOCK_MONOTONIC, &next_wake_ts) != 0)
99 next_wake_ts.tv_sec = 0;
100 next_wake_ts.tv_nsec = 0;
103 struct timespec period_ts;
104 ms_to_timespec(state->config.period_ms, &period_ts);
109#if defined(__linux__)
111 timespec_add_ms(&next_wake_ts, state->config.period_ms);
114 rc = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_wake_ts, NULL);
115 }
while ((rc == EINTR) && (state->should_stop == 0));
117 struct timespec remaining = period_ts;
122 rc = nanosleep(&remaining, &remaining);
123 }
while ((rc != 0) && (errno == EINTR) && (state->should_stop == 0));
126 if (state->should_stop != 0)
131 state->config.callback(state->self_handle, state->config.user_ctx);
133 if (state->config.mode != SAPI_TIMER_MODE_PERIODIC)
143static sapi_status_t backend_create(sapi_timer_storage_t *storage,
const sapi_timer_config_t *config,
144 sapi_timer_handle_t *out_handle)
148 if ((storage == NULL) || (config == NULL) || (out_handle == NULL) || (config->callback == NULL)
149 || (config->period_ms == 0U))
151 return SAPI_STATUS_INVALID_PARAM;
155 sapi_mem_set(state, 0,
sizeof(*state));
156 state->config = *config;
157 state->self_handle = (sapi_timer_handle_t)(
void *)storage;
158 *out_handle = state->self_handle;
159 return SAPI_STATUS_OK;
162static sapi_status_t backend_stop(sapi_timer_handle_t handle)
168 return SAPI_STATUS_INVALID_PARAM;
170 if (state->running != 0)
172 state->should_stop = 1;
173 (void)pthread_join(state->thread, NULL);
176 return SAPI_STATUS_OK;
179static sapi_status_t backend_start(sapi_timer_handle_t handle)
182 sapi_status_t stop_status;
186 return SAPI_STATUS_INVALID_PARAM;
191 stop_status = backend_stop(handle);
192 if (stop_status != SAPI_STATUS_OK)
197 state->should_stop = 0;
198 if (pthread_create(&state->thread, NULL, timer_thread_main, state) != 0)
200 return SAPI_STATUS_INTERNAL_ERROR;
203 return SAPI_STATUS_OK;
206static sapi_status_t backend_destroy(sapi_timer_handle_t handle)
208 return backend_stop(handle);
211static sapi_status_t backend_now(sapi_timestamp_ms_t *out_now_ms)
215 if (out_now_ms == NULL)
217 return SAPI_STATUS_INVALID_PARAM;
219 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
222 return SAPI_STATUS_INTERNAL_ERROR;
224 *out_now_ms = (sapi_timestamp_ms_t)(((uint64_t)ts.tv_sec * 1000ULL) + ((uint64_t)ts.tv_nsec / 1000000ULL));
225 return SAPI_STATUS_OK;
Real POSIX/Linux backend for every OAL service (ADR-018).
const sapi_timer_backend_t * sapi_posix_backend_timer(void)
The POSIX sapi_timer backend (one pthread per timer).
static const sapi_timer_backend_t s_posix_timer_backend