kernel: POSIX: Compatibility layer for POSIX timer APIs.
This patch provides POSIX timer APIs for POSIX 1003.1 PSE52 standard. Signed-off-by: Youvedeep Singh <youvedeep.singh@intel.com>
This commit is contained in:
parent
f0b678b03b
commit
8d040f1bcb
7 changed files with 297 additions and 5 deletions
|
@ -32,8 +32,11 @@
|
||||||
#define pthread_barrierattr_t zap_pthread_barrierattr_t
|
#define pthread_barrierattr_t zap_pthread_barrierattr_t
|
||||||
#define pthread_attr_t zap_pthread_attr_t
|
#define pthread_attr_t zap_pthread_attr_t
|
||||||
#define clockid_t zap_clockid_t
|
#define clockid_t zap_clockid_t
|
||||||
#define sched_param zap_sched_param
|
#define sched_param zap_sched_param
|
||||||
|
#define itimerspe zap_sched_param
|
||||||
|
#define timer_t zap_timer_t
|
||||||
|
#define sigval zap_sigval
|
||||||
|
#define sigevent zap_sigevent
|
||||||
/* Condition variables */
|
/* Condition variables */
|
||||||
#define pthread_cond_init(...) zap_pthread_cond_init(__VA_ARGS__)
|
#define pthread_cond_init(...) zap_pthread_cond_init(__VA_ARGS__)
|
||||||
#define pthread_cond_destroy(...) zap_pthread_cond_destroy(__VA_ARGS__)
|
#define pthread_cond_destroy(...) zap_pthread_cond_destroy(__VA_ARGS__)
|
||||||
|
@ -105,6 +108,12 @@
|
||||||
#define clock_gettime(...) zap_clock_gettime(__VA_ARGS__)
|
#define clock_gettime(...) zap_clock_gettime(__VA_ARGS__)
|
||||||
#define clock_settime(...) zap_clock_settime(__VA_ARGS__)
|
#define clock_settime(...) zap_clock_settime(__VA_ARGS__)
|
||||||
|
|
||||||
|
/* Timer */
|
||||||
|
#define timer_create(...) zap_timer_create(__VA_ARGS__)
|
||||||
|
#define timer_delete(...) zap_timer_delete(__VA_ARGS__)
|
||||||
|
#define timer_gettime(...) zap_timer_gettime(__VA_ARGS__)
|
||||||
|
#define timer_settime(...) zap_timer_settime(__VA_ARGS__)
|
||||||
|
|
||||||
#endif /* CONFIG_ARCH_POSIX */
|
#endif /* CONFIG_ARCH_POSIX */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
44
include/posix/signal.h
Normal file
44
include/posix/signal.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Intel Corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#ifndef __POSIX_SIGNAL_H__
|
||||||
|
#define __POSIX_SIGNAL_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "sys/types.h"
|
||||||
|
|
||||||
|
#ifndef SIGEV_NONE
|
||||||
|
#define SIGEV_NONE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SIGEV_SIGNAL
|
||||||
|
#define SIGEV_SIGNAL 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SIGEV_THREAD
|
||||||
|
#define SIGEV_THREAD 3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef union sigval {
|
||||||
|
int sival_int;
|
||||||
|
void *sival_ptr;
|
||||||
|
} sigval;
|
||||||
|
|
||||||
|
typedef struct sigevent {
|
||||||
|
int sigev_notify;
|
||||||
|
int sigev_signo;
|
||||||
|
sigval sigev_value;
|
||||||
|
void (*sigev_notify_function)(sigval val);
|
||||||
|
pthread_attr_t *sigev_notify_attributes;
|
||||||
|
} sigevent;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __POSIX_TIME_H__ */
|
|
@ -60,6 +60,7 @@ typedef struct pthread_barrierattr {
|
||||||
#ifndef CONFIG_NEWLIB_LIBC
|
#ifndef CONFIG_NEWLIB_LIBC
|
||||||
typedef u32_t clockid_t;
|
typedef u32_t clockid_t;
|
||||||
#endif /*CONFIG_NEWLIB_LIBC */
|
#endif /*CONFIG_NEWLIB_LIBC */
|
||||||
|
typedef unsigned long timer_t;
|
||||||
typedef unsigned long useconds_t;
|
typedef unsigned long useconds_t;
|
||||||
|
|
||||||
#endif /* CONFIG_PTHREAD_IPC */
|
#endif /* CONFIG_PTHREAD_IPC */
|
||||||
|
|
|
@ -14,19 +14,38 @@ extern "C" {
|
||||||
#include_next <time.h>
|
#include_next <time.h>
|
||||||
#else
|
#else
|
||||||
struct timespec {
|
struct timespec {
|
||||||
s32_t tv_sec;
|
signed int tv_sec;
|
||||||
s32_t tv_nsec;
|
signed int tv_nsec;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct itimerspec {
|
||||||
|
struct timespec it_interval; /* Timer interval */
|
||||||
|
struct timespec it_value; /* Timer expiration */
|
||||||
};
|
};
|
||||||
#endif /* CONFIG_NEWLIB_LIBC */
|
#endif /* CONFIG_NEWLIB_LIBC */
|
||||||
|
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "sys/types.h"
|
#include "sys/types.h"
|
||||||
|
#include "signal.h"
|
||||||
|
|
||||||
|
#ifndef CLOCK_REALTIME
|
||||||
|
#define CLOCK_REALTIME 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CLOCK_MONOTONIC
|
||||||
#define CLOCK_MONOTONIC 1
|
#define CLOCK_MONOTONIC 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NSEC_PER_MSEC (NSEC_PER_USEC * USEC_PER_MSEC)
|
||||||
|
|
||||||
|
#ifndef TIMER_ABSTIME
|
||||||
|
#define TIMER_ABSTIME 4
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline s32_t _ts_to_ms(const struct timespec *to)
|
static inline s32_t _ts_to_ms(const struct timespec *to)
|
||||||
{
|
{
|
||||||
return (to->tv_sec * 1000) + (to->tv_nsec / 1000000);
|
return (to->tv_sec * MSEC_PER_SEC) + (to->tv_nsec / NSEC_PER_MSEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,6 +60,12 @@ static inline int clock_settime(clockid_t clock_id, const struct timespec *ts)
|
||||||
}
|
}
|
||||||
|
|
||||||
int clock_gettime(clockid_t clock_id, struct timespec *ts);
|
int clock_gettime(clockid_t clock_id, struct timespec *ts);
|
||||||
|
/* Timer APIs */
|
||||||
|
int timer_create(clockid_t clockId, struct sigevent *evp, timer_t *timerid);
|
||||||
|
int timer_delete(timer_t timerid);
|
||||||
|
int timer_gettime(timer_t timerid, struct itimerspec *its);
|
||||||
|
int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
|
||||||
|
struct itimerspec *ovalue);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -512,6 +512,14 @@ config MAX_PTHREAD_COUNT
|
||||||
range 0 255
|
range 0 255
|
||||||
help
|
help
|
||||||
Mention maximum number of threads in POSIX compliant application.
|
Mention maximum number of threads in POSIX compliant application.
|
||||||
|
|
||||||
|
config MAX_TIMER_COUNT
|
||||||
|
int
|
||||||
|
prompt "Maximum timer count in POSIX application"
|
||||||
|
default 5
|
||||||
|
range 0 255
|
||||||
|
help
|
||||||
|
Mention maximum number of timers in POSIX compliant application.
|
||||||
endif
|
endif
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
|
|
|
@ -5,3 +5,4 @@ target_sources(kernel PRIVATE posix/pthread_barrier.c)
|
||||||
target_sources(kernel PRIVATE posix/pthread.c)
|
target_sources(kernel PRIVATE posix/pthread.c)
|
||||||
target_sources(kernel PRIVATE posix/pthread_sched.c)
|
target_sources(kernel PRIVATE posix/pthread_sched.c)
|
||||||
target_sources(kernel PRIVATE posix/clock.c)
|
target_sources(kernel PRIVATE posix/clock.c)
|
||||||
|
target_sources(kernel PRIVATE posix/timer.c)
|
||||||
|
|
204
kernel/posix/timer.c
Normal file
204
kernel/posix/timer.c
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Intel Corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <misc/printk.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 == 0) {
|
||||||
|
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, 100) == 0) {
|
||||||
|
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 = 0;
|
||||||
|
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 / sys_clock_ticks_per_sec;
|
||||||
|
leftover = remaining - (secs * sys_clock_ticks_per_sec);
|
||||||
|
nsecs = leftover * NSEC_PER_SEC / sys_clock_ticks_per_sec;
|
||||||
|
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) {
|
||||||
|
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) {
|
||||||
|
current = k_timer_remaining_get(&timer->ztimer);
|
||||||
|
|
||||||
|
if (current >= duration) {
|
||||||
|
duration = 0;
|
||||||
|
} else {
|
||||||
|
duration -= current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timer->status == ACTIVE) {
|
||||||
|
k_timer_stop(&timer->ztimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
timer->status = ACTIVE;
|
||||||
|
k_timer_start(&timer->ztimer, duration, 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;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue