Skip to content

Commit 51f9b00

Browse files
committed
posix: add timerfd interface
This is a wrapper around zvfs_timerfd, so we provide a standard POSIX "compatible" timerfd interface. Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
1 parent 1f04ad1 commit 51f9b00

File tree

7 files changed

+171
-0
lines changed

7 files changed

+171
-0
lines changed

include/zephyr/posix/sys/timerfd.h

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright (c) 2020 Tobias Svehagen
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_INCLUDE_POSIX_SYS_TIMERFD_H_
8+
#define ZEPHYR_INCLUDE_POSIX_SYS_TIMERFD_H_
9+
10+
// #include <zephyr/posix/posix_time.h>
11+
#include <zephyr/zvfs/timerfd.h>
12+
#include <time.h>
13+
14+
#ifdef __cplusplus
15+
extern "C" {
16+
#endif
17+
18+
// #define EFD_SEMAPHORE ZVFS_EFD_SEMAPHORE
19+
#define TFD_NONBLOCK ZVFS_TFD_NONBLOCK
20+
21+
#define TFD_IOC_SET_TICKS ZVFS_TFD_IOC_SET_TICKS
22+
// #define TFD_TIMER_ABSTIME ZVFS_TFD_TIMER_ABSTIME
23+
24+
#define TFD_TIMER_ABSTIME 1
25+
26+
typedef zvfs_timerfd_t timerfd_t;
27+
28+
/**
29+
* @brief Create a file descriptor for ZVFS event notification
30+
*
31+
* The returned file descriptor can be used with POSIX read/write calls or
32+
* with the @ref zvfs_timerfd_read or @ref zvfs_timerfd_write functions.
33+
*
34+
* It also supports polling and by including an timerfd in a call to poll,
35+
* it is possible to signal and wake the polling thread by simply writing to
36+
* the timerfd.
37+
*
38+
* When using read() and write() on a ZVFS timerfd, the size must always be at
39+
* least 8 bytes or the operation will fail with EINVAL.
40+
*
41+
* @return New ZVFS timerfd file descriptor on success, -1 on error
42+
*/
43+
int timerfd_create(int clockid, int flags);
44+
45+
/**
46+
* @brief Write to a ZVFS timerfd
47+
*
48+
* @param fd File descriptor
49+
* @param value Value to write
50+
*
51+
* @return 0 on success, -1 on error
52+
*/
53+
int timerfd_gettime(int fd, struct itimerspec *curr_value);
54+
55+
/**
56+
* @brief Write to a ZVFS timerfd
57+
*
58+
* @param fd File descriptor
59+
* @param value Value to write
60+
*
61+
* @return 0 on success, -1 on error
62+
*/
63+
int timerfd_settime(int fd, int flags, const struct itimerspec *new_value,
64+
struct itimerspec *old_value);
65+
66+
#ifdef __cplusplus
67+
}
68+
#endif
69+
70+
#endif /* ZEPHYR_INCLUDE_POSIX_SYS_TIMERFD_H_ */

lib/posix/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
# zephyr-keep-sorted-start
44
add_subdirectory_ifdef(CONFIG_EVENTFD eventfd)
5+
add_subdirectory_ifdef(CONFIG_TIMERFD timerfd)
56
add_subdirectory_ifdef(CONFIG_POSIX_C_LANG_SUPPORT_R c_lang_support_r)
67
add_subdirectory_ifdef(CONFIG_POSIX_C_LIB_EXT c_lib_ext)
78
add_subdirectory_ifdef(CONFIG_POSIX_SHELL shell)

lib/posix/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,6 @@ endmenu
4242

4343
# Eventfd Support (not officially POSIX)
4444
rsource "eventfd/Kconfig"
45+
46+
# Timerfd Support (not officially POSIX)
47+
rsource "timerfd/Kconfig"

lib/posix/Kconfig.profile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ config POSIX_API
1515
select POSIX_AEP_REALTIME_MINIMAL # CLOCK_MONOTONIC, pthread_attr_setstack(), etc
1616
select POSIX_NETWORKING if NETWORKING # inet_ntoa(), socket(), etc
1717
imply EVENTFD # eventfd(), eventfd_read(), eventfd_write()
18+
imply TIMERFD # timerfd_create(), timerfd_settime(), timerfd_gettime()
1819
imply POSIX_FD_MGMT # open(), close(), read(), write()
1920
imply POSIX_MULTI_PROCESS # sleep(), getpid(), etc
2021
imply XSI_SINGLE_PROCESS # gettimeofday()

lib/posix/timerfd/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
zephyr_library()
4+
zephyr_library_sources(timerfd.c)

lib/posix/timerfd/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright (c) 2025 Atym, Inc.
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
config TIMERFD
6+
bool "Support for timerfd"
7+
select ZVFS
8+
select ZVFS_TIMERFD
9+
help
10+
Enable support for timer file descriptors, timerfd. A timerfd can
11+
be used as an timer waiting mechanism together with POSIX calls
12+
like read, write and poll.

lib/posix/timerfd/timerfd.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (c) 2024, Tenstorrent AI ULC
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include "../options/posix_clock.h"
8+
#include <string.h>
9+
10+
#include <zephyr/posix/sys/timerfd.h>
11+
#include <zephyr/zvfs/timerfd.h>
12+
13+
int timerfd_create(int clockid, int flags)
14+
{
15+
return zvfs_timerfd(clockid, flags);
16+
};
17+
18+
int timerfd_gettime(int fd, struct itimerspec *curr_value)
19+
{
20+
int ret;
21+
uint32_t value, period;
22+
int32_t leftover;
23+
int64_t nsecs, secs;
24+
25+
ret = zvfs_timerfd_gettime(fd, &value, &period);
26+
if (ret != 0) {
27+
return ret;
28+
}
29+
30+
/* converts value */
31+
secs = value / MSEC_PER_SEC;
32+
leftover = value - (secs * MSEC_PER_SEC);
33+
nsecs = (int64_t)leftover * NSEC_PER_MSEC;
34+
curr_value->it_value.tv_sec = (int32_t) secs;
35+
curr_value->it_value.tv_nsec = (int32_t) nsecs;
36+
37+
/* converts period */
38+
secs = period / MSEC_PER_SEC;
39+
leftover = period - (secs * MSEC_PER_SEC);
40+
nsecs = (int64_t)leftover * NSEC_PER_MSEC;
41+
curr_value->it_interval.tv_sec = (int32_t) secs;
42+
curr_value->it_interval.tv_nsec = (int32_t) nsecs;
43+
44+
return 0;
45+
};
46+
47+
int timerfd_settime(int fd, int flags, const struct itimerspec *new_value,
48+
struct itimerspec *old_value)
49+
{
50+
uint32_t period, duration, current;
51+
52+
if (!timespec_is_valid(&new_value->it_interval) ||
53+
!timespec_is_valid(&new_value->it_value)) {
54+
errno = EINVAL;
55+
return -1;
56+
}
57+
58+
/* Save time to expire and old reload value. */
59+
if (old_value != NULL) {
60+
timerfd_gettime(fd, old_value);
61+
}
62+
63+
/* Calculate timer duration */
64+
duration = ts_to_ms(&(new_value->it_value));
65+
66+
/* Calculate timer period */
67+
period = ts_to_ms(&(new_value->it_interval));
68+
69+
if ((flags & TFD_TIMER_ABSTIME) != 0) {
70+
zvfs_timerfd_gettime(fd, &current, NULL);
71+
72+
if (current >= duration) {
73+
duration = 0U;
74+
} else {
75+
duration -= current;
76+
}
77+
}
78+
79+
return zvfs_timerfd_settime(fd, K_MSEC(duration), K_MSEC(period));
80+
}

0 commit comments

Comments
 (0)