summaryrefslogtreecommitdiffstats
path: root/src/select.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2017-12-03 16:13:39 +0100
committerHarald Welte <laforge@gnumonks.org>2018-05-10 10:33:54 +0200
commitea4d8939af7204bc6ca76144354ef4d70189eaa3 (patch)
tree9e9259f5a73620508ac4e2dedcff7e6cf35482fc /src/select.c
parentb82a407a4924f51844c01e1627c3bb01db210c0f (diff)
Add osmo_timerfd_* functions for osmo_fd-wrapped timerfd
Linux offers file descriptor based periodic (interval) timers, which can achieve a higher precision than our userspace based timers and which can be slave'd to CLOCK_MONOTINIC or other clock sources. Let's add some code for osmo_fd wrapped versions that integrate well with our select() abstraction. The code has been used in osmo-bts-trx since June 2017 (change-id I51b19adde14ebb7ef3bb863d45e06243c323e22e), and I'm just renaming and moving it to libosmocore here. After a merge, the osmo-bts implementations can be removed in favor if this one. Change-Id: Ibeffba7c997252c003723bcd5d14122c4ded2fe7
Diffstat (limited to 'src/select.c')
-rw-r--r--src/select.c66
1 files changed, 66 insertions, 0 deletions
diff --git a/src/select.c b/src/select.c
index 1c62e011..0b115c61 100644
--- a/src/select.c
+++ b/src/select.c
@@ -30,6 +30,7 @@
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
+#include <errno.h>
#include <osmocom/core/select.h>
#include <osmocom/core/linuxlist.h>
@@ -270,6 +271,71 @@ struct osmo_fd *osmo_fd_get_by_fd(int fd)
return NULL;
}
+#ifdef HAVE_SYS_TIMERFD_H
+#include <sys/timerfd.h>
+
+/*! disable the osmocom-wrapped timerfd */
+int osmo_timerfd_disable(struct osmo_fd *ofd)
+{
+ const struct itimerspec its_null = {
+ .it_value = { 0, 0 },
+ .it_interval = { 0, 0 },
+ };
+ return timerfd_settime(ofd->fd, 0, &its_null, NULL);
+}
+
+/*! schedule the osmcoom-wrapped timerfd to occur first at \a first, then periodically at \a interval
+ * \param[in] ofd Osmocom wrapped timerfd
+ * \param[in] first Relative time at which the timer should first execute (NULL = \a interval)
+ * \param[in] interval Time interval at which subsequent timer shall fire
+ * \returns 0 on success; negative on error */
+int osmo_timerfd_schedule(struct osmo_fd *ofd, const struct timespec *first,
+ const struct timespec *interval)
+{
+ struct itimerspec its;
+
+ if (ofd->fd < 0)
+ return -EINVAL;
+
+ /* first expiration */
+ if (first)
+ its.it_value = *first;
+ else
+ its.it_value = *interval;
+ /* repeating interval */
+ its.it_interval = *interval;
+
+ return timerfd_settime(ofd->fd, 0, &its, NULL);
+}
+
+/*! setup osmocom-wrapped timerfd
+ * \param[inout] ofd Osmocom-wrapped timerfd on which to operate
+ * \param[in] cb Call-back function called when timerfd becomes readable
+ * \param[in] data Opaque data to be passed on to call-back
+ * \returns 0 on success; negative on error
+ *
+ * We simply initialize the data structures here, but do not yet
+ * schedule the timer.
+ */
+int osmo_timerfd_setup(struct osmo_fd *ofd, int (*cb)(struct osmo_fd *, unsigned int), void *data)
+{
+ ofd->cb = cb;
+ ofd->data = data;
+ ofd->when = BSC_FD_READ;
+
+ if (ofd->fd < 0) {
+ ofd->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
+ if (ofd->fd < 0)
+ return ofd->fd;
+
+ osmo_fd_register(ofd);
+ }
+ return 0;
+}
+
+#endif /* HAVE_SYS_TIMERFD_H */
+
+
/*! @} */
#endif /* _HAVE_SYS_SELECT_H */