Skip to content

Commit 8d040f1

Browse files
youvedeep-singhAnas Nashif
authored andcommitted
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 <[email protected]>
1 parent f0b678b commit 8d040f1

File tree

7 files changed

+297
-5
lines changed

7 files changed

+297
-5
lines changed

arch/posix/include/posix_cheats.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,11 @@
3232
#define pthread_barrierattr_t zap_pthread_barrierattr_t
3333
#define pthread_attr_t zap_pthread_attr_t
3434
#define clockid_t zap_clockid_t
35-
#define sched_param zap_sched_param
36-
35+
#define sched_param zap_sched_param
36+
#define itimerspe zap_sched_param
37+
#define timer_t zap_timer_t
38+
#define sigval zap_sigval
39+
#define sigevent zap_sigevent
3740
/* Condition variables */
3841
#define pthread_cond_init(...) zap_pthread_cond_init(__VA_ARGS__)
3942
#define pthread_cond_destroy(...) zap_pthread_cond_destroy(__VA_ARGS__)
@@ -105,6 +108,12 @@
105108
#define clock_gettime(...) zap_clock_gettime(__VA_ARGS__)
106109
#define clock_settime(...) zap_clock_settime(__VA_ARGS__)
107110

111+
/* Timer */
112+
#define timer_create(...) zap_timer_create(__VA_ARGS__)
113+
#define timer_delete(...) zap_timer_delete(__VA_ARGS__)
114+
#define timer_gettime(...) zap_timer_gettime(__VA_ARGS__)
115+
#define timer_settime(...) zap_timer_settime(__VA_ARGS__)
116+
108117
#endif /* CONFIG_ARCH_POSIX */
109118

110119
#endif

include/posix/signal.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (c) 2018 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#ifndef __POSIX_SIGNAL_H__
7+
#define __POSIX_SIGNAL_H__
8+
9+
#ifdef __cplusplus
10+
extern "C" {
11+
#endif
12+
13+
#include "sys/types.h"
14+
15+
#ifndef SIGEV_NONE
16+
#define SIGEV_NONE 1
17+
#endif
18+
19+
#ifndef SIGEV_SIGNAL
20+
#define SIGEV_SIGNAL 2
21+
#endif
22+
23+
#ifndef SIGEV_THREAD
24+
#define SIGEV_THREAD 3
25+
#endif
26+
27+
typedef union sigval {
28+
int sival_int;
29+
void *sival_ptr;
30+
} sigval;
31+
32+
typedef struct sigevent {
33+
int sigev_notify;
34+
int sigev_signo;
35+
sigval sigev_value;
36+
void (*sigev_notify_function)(sigval val);
37+
pthread_attr_t *sigev_notify_attributes;
38+
} sigevent;
39+
40+
#ifdef __cplusplus
41+
}
42+
#endif
43+
44+
#endif /* __POSIX_TIME_H__ */

include/posix/sys/types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ typedef struct pthread_barrierattr {
6060
#ifndef CONFIG_NEWLIB_LIBC
6161
typedef u32_t clockid_t;
6262
#endif /*CONFIG_NEWLIB_LIBC */
63+
typedef unsigned long timer_t;
6364
typedef unsigned long useconds_t;
6465

6566
#endif /* CONFIG_PTHREAD_IPC */

include/posix/time.h

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,38 @@ extern "C" {
1414
#include_next <time.h>
1515
#else
1616
struct timespec {
17-
s32_t tv_sec;
18-
s32_t tv_nsec;
17+
signed int tv_sec;
18+
signed int tv_nsec;
19+
};
20+
21+
struct itimerspec {
22+
struct timespec it_interval; /* Timer interval */
23+
struct timespec it_value; /* Timer expiration */
1924
};
2025
#endif /* CONFIG_NEWLIB_LIBC */
26+
2127
#include <kernel.h>
2228
#include <errno.h>
2329
#include "sys/types.h"
30+
#include "signal.h"
31+
32+
#ifndef CLOCK_REALTIME
33+
#define CLOCK_REALTIME 0
34+
#endif
2435

36+
#ifndef CLOCK_MONOTONIC
2537
#define CLOCK_MONOTONIC 1
38+
#endif
39+
40+
#define NSEC_PER_MSEC (NSEC_PER_USEC * USEC_PER_MSEC)
41+
42+
#ifndef TIMER_ABSTIME
43+
#define TIMER_ABSTIME 4
44+
#endif
2645

2746
static inline s32_t _ts_to_ms(const struct timespec *to)
2847
{
29-
return (to->tv_sec * 1000) + (to->tv_nsec / 1000000);
48+
return (to->tv_sec * MSEC_PER_SEC) + (to->tv_nsec / NSEC_PER_MSEC);
3049
}
3150

3251
/**
@@ -41,6 +60,12 @@ static inline int clock_settime(clockid_t clock_id, const struct timespec *ts)
4160
}
4261

4362
int clock_gettime(clockid_t clock_id, struct timespec *ts);
63+
/* Timer APIs */
64+
int timer_create(clockid_t clockId, struct sigevent *evp, timer_t *timerid);
65+
int timer_delete(timer_t timerid);
66+
int timer_gettime(timer_t timerid, struct itimerspec *its);
67+
int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
68+
struct itimerspec *ovalue);
4469

4570
#ifdef __cplusplus
4671
}

kernel/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,14 @@ config MAX_PTHREAD_COUNT
512512
range 0 255
513513
help
514514
Mention maximum number of threads in POSIX compliant application.
515+
516+
config MAX_TIMER_COUNT
517+
int
518+
prompt "Maximum timer count in POSIX application"
519+
default 5
520+
range 0 255
521+
help
522+
Mention maximum number of timers in POSIX compliant application.
515523
endif
516524
endmenu
517525

kernel/posix/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ target_sources(kernel PRIVATE posix/pthread_barrier.c)
55
target_sources(kernel PRIVATE posix/pthread.c)
66
target_sources(kernel PRIVATE posix/pthread_sched.c)
77
target_sources(kernel PRIVATE posix/clock.c)
8+
target_sources(kernel PRIVATE posix/timer.c)

kernel/posix/timer.c

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/*
2+
* Copyright (c) 2018 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#include <kernel.h>
7+
#include <time.h>
8+
#include <errno.h>
9+
#include <string.h>
10+
#include <misc/printk.h>
11+
12+
#define ACTIVE 1
13+
#define NOT_ACTIVE 0
14+
15+
static void zephyr_timer_wrapper(struct k_timer *timer);
16+
17+
struct timer_obj {
18+
struct k_timer ztimer;
19+
void (*sigev_notify_function)(sigval val);
20+
sigval val;
21+
struct timespec interval; /* Reload value */
22+
u32_t reload; /* Reload value in ms */
23+
u32_t status;
24+
};
25+
26+
K_MEM_SLAB_DEFINE(posix_timer_slab, sizeof(struct timer_obj),
27+
CONFIG_MAX_TIMER_COUNT, 4);
28+
29+
static void zephyr_timer_wrapper(struct k_timer *ztimer)
30+
{
31+
struct timer_obj *timer;
32+
33+
timer = (struct timer_obj *)ztimer;
34+
35+
if (timer->reload == 0) {
36+
timer->status = NOT_ACTIVE;
37+
}
38+
39+
(timer->sigev_notify_function)(timer->val);
40+
}
41+
42+
/**
43+
* @brief Create a per-process timer.
44+
*
45+
* This API does not accept SIGEV_THREAD as valid signal event notification
46+
* type.
47+
*
48+
* See IEEE 1003.1
49+
*/
50+
int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)
51+
{
52+
struct timer_obj *timer;
53+
54+
if (clockid != CLOCK_MONOTONIC || evp == NULL ||
55+
(evp->sigev_notify != SIGEV_NONE &&
56+
evp->sigev_notify != SIGEV_SIGNAL)) {
57+
errno = EINVAL;
58+
return -1;
59+
}
60+
61+
if (k_mem_slab_alloc(&posix_timer_slab, (void **)&timer, 100) == 0) {
62+
memset(timer, 0, sizeof(struct timer_obj));
63+
} else {
64+
errno = ENOMEM;
65+
return -1;
66+
}
67+
68+
timer->sigev_notify_function = evp->sigev_notify_function;
69+
timer->val = evp->sigev_value;
70+
timer->interval.tv_sec = 0;
71+
timer->interval.tv_nsec = 0;
72+
timer->reload = 0;
73+
timer->status = NOT_ACTIVE;
74+
75+
if (evp->sigev_notify == SIGEV_NONE) {
76+
k_timer_init(&timer->ztimer, NULL, NULL);
77+
} else {
78+
k_timer_init(&timer->ztimer, zephyr_timer_wrapper, NULL);
79+
}
80+
81+
*timerid = (timer_t)timer;
82+
83+
return 0;
84+
}
85+
86+
/**
87+
* @brief Get amount of time left for expiration on a per-process timer.
88+
*
89+
* See IEEE 1003.1
90+
*/
91+
int timer_gettime(timer_t timerid, struct itimerspec *its)
92+
{
93+
struct timer_obj *timer = (struct timer_obj *)timerid;
94+
s32_t remaining, leftover;
95+
s64_t nsecs, secs;
96+
97+
if (timer == NULL) {
98+
errno = EINVAL;
99+
return -1;
100+
}
101+
102+
if (timer->status == ACTIVE) {
103+
remaining = k_timer_remaining_get(&timer->ztimer);
104+
secs = remaining / sys_clock_ticks_per_sec;
105+
leftover = remaining - (secs * sys_clock_ticks_per_sec);
106+
nsecs = leftover * NSEC_PER_SEC / sys_clock_ticks_per_sec;
107+
its->it_value.tv_sec = (s32_t) secs;
108+
its->it_value.tv_nsec = (s32_t) nsecs;
109+
} else {
110+
/* Timer is disarmed */
111+
its->it_value.tv_sec = 0;
112+
its->it_value.tv_nsec = 0;
113+
}
114+
115+
/* The interval last set by timer_settime() */
116+
its->it_interval = timer->interval;
117+
return 0;
118+
}
119+
120+
/**
121+
* @brief Sets expiration time of per-process timer.
122+
*
123+
* See IEEE 1003.1
124+
*/
125+
int timer_settime(timer_t timerid, int flags, const struct itimerspec *value,
126+
struct itimerspec *ovalue)
127+
{
128+
struct timer_obj *timer = (struct timer_obj *) timerid;
129+
u32_t duration, current;
130+
131+
if (timer == NULL ||
132+
value->it_interval.tv_nsec < 0 ||
133+
value->it_interval.tv_nsec >= NSEC_PER_SEC ||
134+
value->it_value.tv_nsec < 0 ||
135+
value->it_value.tv_nsec >= NSEC_PER_SEC) {
136+
errno = EINVAL;
137+
return -1;
138+
}
139+
140+
/* Save time to expire and old reload value. */
141+
if (ovalue) {
142+
timer_gettime(timerid, ovalue);
143+
}
144+
145+
/* Stop the timer if the value is 0 */
146+
if ((value->it_value.tv_sec == 0) && (value->it_value.tv_nsec == 0)) {
147+
if (timer->status == ACTIVE) {
148+
k_timer_stop(&timer->ztimer);
149+
}
150+
151+
timer->status = NOT_ACTIVE;
152+
return 0;
153+
}
154+
155+
/* Calculate timer period */
156+
timer->reload = _ts_to_ms(&value->it_interval);
157+
timer->interval.tv_sec = value->it_interval.tv_sec;
158+
timer->interval.tv_nsec = value->it_interval.tv_nsec;
159+
160+
/* Calcaulte timer duration */
161+
duration = _ts_to_ms(&(value->it_value));
162+
if (flags & TIMER_ABSTIME) {
163+
current = k_timer_remaining_get(&timer->ztimer);
164+
165+
if (current >= duration) {
166+
duration = 0;
167+
} else {
168+
duration -= current;
169+
}
170+
}
171+
172+
if (timer->status == ACTIVE) {
173+
k_timer_stop(&timer->ztimer);
174+
}
175+
176+
timer->status = ACTIVE;
177+
k_timer_start(&timer->ztimer, duration, timer->reload);
178+
return 0;
179+
}
180+
181+
/**
182+
* @brief Delete a per-process timer.
183+
*
184+
* See IEEE 1003.1
185+
*/
186+
int timer_delete(timer_t timerid)
187+
{
188+
struct timer_obj *timer = (struct timer_obj *) timerid;
189+
190+
if (timer == NULL) {
191+
errno = EINVAL;
192+
return -1;
193+
}
194+
195+
if (timer->status == ACTIVE) {
196+
timer->status = NOT_ACTIVE;
197+
k_timer_stop(&timer->ztimer);
198+
}
199+
200+
k_mem_slab_free(&posix_timer_slab, (void *) &timer);
201+
202+
return 0;
203+
}
204+

0 commit comments

Comments
 (0)