1#define _POSIX_C_SOURCE 200809L
33#include "safeapi/oal/memory/sapi_mem_util.h"
39 sapi_task_config_t config;
40 volatile sig_atomic_t running;
41 volatile sig_atomic_t should_stop;
42 sapi_task_handle_t self_handle;
47typedef char posix_task_storage_fits_[(
sizeof(
posix_task_state_t) <=
sizeof(sapi_task_storage_t)) ? 1 : -1];
49#if !defined(__linux__)
50static void ms_to_timespec(sapi_duration_ms_t ms,
struct timespec *out_ts)
52 out_ts->tv_sec = (time_t)(ms / 1000U);
53 out_ts->tv_nsec = (long)((ms % 1000U) * 1000000L);
58static void timespec_add_ms(
struct timespec *ts, sapi_duration_ms_t ms)
60 ts->tv_sec += (time_t)(ms / 1000U);
61 ts->tv_nsec += (long)((ms % 1000U) * 1000000L);
62 if (ts->tv_nsec >= 1000000000L)
65 ts->tv_nsec -= 1000000000L;
76 struct sched_param sched;
77 int min_prio = sched_get_priority_min(SCHED_FIFO);
78 int max_prio = sched_get_priority_max(SCHED_FIFO);
81 if ((min_prio < 0) || (max_prio < 0))
86 wanted = (int)priority;
87 if (wanted < min_prio)
91 if (wanted > max_prio)
96 sapi_mem_set(&sched, 0,
sizeof(sched));
97 sched.sched_priority = wanted;
98 (void)pthread_setschedparam(thread, SCHED_FIFO, &sched);
101static void *task_thread_main(
void *arg)
105 if (state->config.period_ms == 0U)
122 state->config.entry(state->config.user_ctx);
126#if defined(__linux__)
127 struct timespec next_wake_ts;
129 if (clock_gettime(CLOCK_MONOTONIC, &next_wake_ts) != 0)
131 next_wake_ts.tv_sec = 0;
132 next_wake_ts.tv_nsec = 0;
135 while (state->should_stop == 0)
138 timespec_add_ms(&next_wake_ts, state->config.period_ms);
141 rc = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_wake_ts, NULL);
142 }
while ((rc == EINTR) && (state->should_stop == 0));
144 if (state->should_stop != 0)
149 state->config.entry(state->config.user_ctx);
152 struct timespec period_ts;
154 ms_to_timespec(state->config.period_ms, &period_ts);
156 while (state->should_stop == 0)
158 struct timespec remaining = period_ts;
163 rc = nanosleep(&remaining, &remaining);
164 }
while ((rc != 0) && (errno == EINTR) && (state->should_stop == 0));
166 if (state->should_stop != 0)
171 state->config.entry(state->config.user_ctx);
180static sapi_status_t backend_create(sapi_task_storage_t *storage,
const sapi_task_config_t *config,
181 sapi_task_handle_t *out_handle)
185 if ((storage == NULL) || (config == NULL) || (out_handle == NULL) || (config->entry == NULL))
187 return SAPI_STATUS_INVALID_PARAM;
191 sapi_mem_set(state, 0,
sizeof(*state));
192 state->config = *config;
193 state->self_handle = (sapi_task_handle_t)(
void *)storage;
194 *out_handle = state->self_handle;
195 return SAPI_STATUS_OK;
198static sapi_status_t backend_suspend(sapi_task_handle_t handle)
204 return SAPI_STATUS_INVALID_PARAM;
206 if (state->running != 0)
208 state->should_stop = 1;
209 (void)pthread_join(state->thread, NULL);
212 return SAPI_STATUS_OK;
215static sapi_status_t backend_start(sapi_task_handle_t handle)
218 sapi_status_t suspend_status;
220 pthread_attr_t *attr_ptr = NULL;
224 return SAPI_STATUS_INVALID_PARAM;
229 suspend_status = backend_suspend(handle);
230 if (suspend_status != SAPI_STATUS_OK)
232 return suspend_status;
235 state->should_stop = 0;
237 if (state->config.stack_size > 0U)
239 if (pthread_attr_init(&attr) == 0)
241 (void)pthread_attr_setstacksize(&attr, state->config.stack_size);
246 if (pthread_create(&state->thread, attr_ptr, task_thread_main, state) != 0)
248 if (attr_ptr != NULL)
250 (void)pthread_attr_destroy(attr_ptr);
252 return SAPI_STATUS_INTERNAL_ERROR;
258 if (attr_ptr != NULL)
260 (void)pthread_attr_destroy(attr_ptr);
262 return SAPI_STATUS_OK;
265static sapi_status_t backend_destroy(sapi_task_handle_t handle)
267 return backend_suspend(handle);
270static const sapi_task_backend_t s_posix_task_backend = { backend_create, backend_start, backend_suspend,
275 return &s_posix_task_backend;
Real POSIX/Linux backend for every OAL service (ADR-018).
const sapi_task_backend_t * sapi_posix_backend_task(void)
The POSIX sapi_task backend (one pthread per task).
static void apply_priority_best_effort(pthread_t thread, uint32_t priority)