123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- /*
- * 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 *ztimer);
- struct timer_obj {
- struct k_timer ztimer;
- void (*sigev_notify_function)(sigval val);
- sigval val;
- struct timespec interval; /* Reload value */
- uint32_t reload; /* Reload value in ms */
- uint32_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;
- int32_t remaining, leftover;
- int64_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 = (int64_t)leftover * NSEC_PER_MSEC;
- its->it_value.tv_sec = (int32_t) secs;
- its->it_value.tv_nsec = (int32_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;
- uint32_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;
- }
|