mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-03 08:11:56 +00:00
Kernel timeouts have always been a 32 bit integer despite the existence of generation macros, and existing code has been inconsistent about using them. Upcoming commits are going to make the timeout arguments opaque, so fix things up to be rigorously correct. Changes include: + Adding a K_TIMEOUT_EQ() macro for code that needs to compare timeout values for equality (e.g. with K_FOREVER or K_NO_WAIT). + Adding a k_msleep() synonym for k_sleep() which can continue to take integral arguments as k_sleep() moves away to timeout arguments. + Pervasively using the K_MSEC(), K_SECONDS(), et. al. macros to generate timeout arguments. + Removing the usage of K_NO_WAIT as the final argument to K_THREAD_DEFINE(). This is just a count of milliseconds and we need to use a zero. This patch include no logic changes and should not affect generated code at all. Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
204 lines
4.4 KiB
C
204 lines
4.4 KiB
C
/*
|
|
* Copyright (c) 2018 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#include <kernel.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <sys/printk.h>
|
|
#include <posix/time.h>
|
|
|
|
#define ACTIVE 1
|
|
#define NOT_ACTIVE 0
|
|
|
|
static void zephyr_timer_wrapper(struct k_timer *timer);
|
|
|
|
struct timer_obj {
|
|
struct k_timer ztimer;
|
|
void (*sigev_notify_function)(sigval val);
|
|
sigval val;
|
|
struct timespec interval; /* Reload value */
|
|
u32_t reload; /* Reload value in ms */
|
|
u32_t status;
|
|
};
|
|
|
|
K_MEM_SLAB_DEFINE(posix_timer_slab, sizeof(struct timer_obj),
|
|
CONFIG_MAX_TIMER_COUNT, 4);
|
|
|
|
static void zephyr_timer_wrapper(struct k_timer *ztimer)
|
|
{
|
|
struct timer_obj *timer;
|
|
|
|
timer = (struct timer_obj *)ztimer;
|
|
|
|
if (timer->reload == 0U) {
|
|
timer->status = NOT_ACTIVE;
|
|
}
|
|
|
|
(timer->sigev_notify_function)(timer->val);
|
|
}
|
|
|
|
/**
|
|
* @brief Create a per-process timer.
|
|
*
|
|
* This API does not accept SIGEV_THREAD as valid signal event notification
|
|
* type.
|
|
*
|
|
* See IEEE 1003.1
|
|
*/
|
|
int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)
|
|
{
|
|
struct timer_obj *timer;
|
|
|
|
if (clockid != CLOCK_MONOTONIC || evp == NULL ||
|
|
(evp->sigev_notify != SIGEV_NONE &&
|
|
evp->sigev_notify != SIGEV_SIGNAL)) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
if (k_mem_slab_alloc(&posix_timer_slab, (void **)&timer, K_MSEC(100)) == 0) {
|
|
(void)memset(timer, 0, sizeof(struct timer_obj));
|
|
} else {
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
|
|
timer->sigev_notify_function = evp->sigev_notify_function;
|
|
timer->val = evp->sigev_value;
|
|
timer->interval.tv_sec = 0;
|
|
timer->interval.tv_nsec = 0;
|
|
timer->reload = 0U;
|
|
timer->status = NOT_ACTIVE;
|
|
|
|
if (evp->sigev_notify == SIGEV_NONE) {
|
|
k_timer_init(&timer->ztimer, NULL, NULL);
|
|
} else {
|
|
k_timer_init(&timer->ztimer, zephyr_timer_wrapper, NULL);
|
|
}
|
|
|
|
*timerid = (timer_t)timer;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Get amount of time left for expiration on a per-process timer.
|
|
*
|
|
* See IEEE 1003.1
|
|
*/
|
|
int timer_gettime(timer_t timerid, struct itimerspec *its)
|
|
{
|
|
struct timer_obj *timer = (struct timer_obj *)timerid;
|
|
s32_t remaining, leftover;
|
|
s64_t nsecs, secs;
|
|
|
|
if (timer == NULL) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
if (timer->status == ACTIVE) {
|
|
remaining = k_timer_remaining_get(&timer->ztimer);
|
|
secs = remaining / MSEC_PER_SEC;
|
|
leftover = remaining - (secs * MSEC_PER_SEC);
|
|
nsecs = (s64_t)leftover * NSEC_PER_MSEC;
|
|
its->it_value.tv_sec = (s32_t) secs;
|
|
its->it_value.tv_nsec = (s32_t) nsecs;
|
|
} else {
|
|
/* Timer is disarmed */
|
|
its->it_value.tv_sec = 0;
|
|
its->it_value.tv_nsec = 0;
|
|
}
|
|
|
|
/* The interval last set by timer_settime() */
|
|
its->it_interval = timer->interval;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Sets expiration time of per-process timer.
|
|
*
|
|
* See IEEE 1003.1
|
|
*/
|
|
int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
|
|
struct itimerspec *ovalue)
|
|
{
|
|
struct timer_obj *timer = (struct timer_obj *) timerid;
|
|
u32_t duration, current;
|
|
|
|
if (timer == NULL ||
|
|
value->it_interval.tv_nsec < 0 ||
|
|
value->it_interval.tv_nsec >= NSEC_PER_SEC ||
|
|
value->it_value.tv_nsec < 0 ||
|
|
value->it_value.tv_nsec >= NSEC_PER_SEC) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
/* Save time to expire and old reload value. */
|
|
if (ovalue != NULL) {
|
|
timer_gettime(timerid, ovalue);
|
|
}
|
|
|
|
/* Stop the timer if the value is 0 */
|
|
if ((value->it_value.tv_sec == 0) && (value->it_value.tv_nsec == 0)) {
|
|
if (timer->status == ACTIVE) {
|
|
k_timer_stop(&timer->ztimer);
|
|
}
|
|
|
|
timer->status = NOT_ACTIVE;
|
|
return 0;
|
|
}
|
|
|
|
/* Calculate timer period */
|
|
timer->reload = _ts_to_ms(&value->it_interval);
|
|
timer->interval.tv_sec = value->it_interval.tv_sec;
|
|
timer->interval.tv_nsec = value->it_interval.tv_nsec;
|
|
|
|
/* Calcaulte timer duration */
|
|
duration = _ts_to_ms(&(value->it_value));
|
|
if ((flags & TIMER_ABSTIME) != 0) {
|
|
current = k_timer_remaining_get(&timer->ztimer);
|
|
|
|
if (current >= duration) {
|
|
duration = 0U;
|
|
} else {
|
|
duration -= current;
|
|
}
|
|
}
|
|
|
|
if (timer->status == ACTIVE) {
|
|
k_timer_stop(&timer->ztimer);
|
|
}
|
|
|
|
timer->status = ACTIVE;
|
|
k_timer_start(&timer->ztimer, K_MSEC(duration), K_MSEC(timer->reload));
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Delete a per-process timer.
|
|
*
|
|
* See IEEE 1003.1
|
|
*/
|
|
int timer_delete(timer_t timerid)
|
|
{
|
|
struct timer_obj *timer = (struct timer_obj *) timerid;
|
|
|
|
if (timer == NULL) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
if (timer->status == ACTIVE) {
|
|
timer->status = NOT_ACTIVE;
|
|
k_timer_stop(&timer->ztimer);
|
|
}
|
|
|
|
k_mem_slab_free(&posix_timer_slab, (void *) &timer);
|
|
|
|
return 0;
|
|
}
|