diff options
| author | Harald Welte <laforge@gnumonks.org> | 2017-12-03 16:13:39 +0100 | 
|---|---|---|
| committer | Harald Welte <laforge@gnumonks.org> | 2018-05-10 10:33:54 +0200 | 
| commit | ea4d8939af7204bc6ca76144354ef4d70189eaa3 (patch) | |
| tree | 9e9259f5a73620508ac4e2dedcff7e6cf35482fc | |
| parent | b82a407a4924f51844c01e1627c3bb01db210c0f (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
| -rw-r--r-- | configure.ac | 2 | ||||
| -rw-r--r-- | include/osmocom/core/select.h | 7 | ||||
| -rw-r--r-- | src/select.c | 66 | 
3 files changed, 74 insertions, 1 deletions
| diff --git a/configure.ac b/configure.ac index 6f561767..6b9c66f1 100644 --- a/configure.ac +++ b/configure.ac @@ -55,7 +55,7 @@ AC_SUBST(LTLDFLAGS_OSMOCODING)  dnl checks for header files  AC_HEADER_STDC -AC_CHECK_HEADERS(execinfo.h sys/select.h sys/socket.h syslog.h ctype.h netinet/tcp.h) +AC_CHECK_HEADERS(execinfo.h sys/select.h sys/socket.h sys/timerfd.h syslog.h ctype.h netinet/tcp.h)  # for src/conv.c  AC_FUNC_ALLOCA  AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DLOPEN="$LIBS";LIBS=""]) diff --git a/include/osmocom/core/select.h b/include/osmocom/core/select.h index b6fed3c7..1ba6b832 100644 --- a/include/osmocom/core/select.h +++ b/include/osmocom/core/select.h @@ -6,6 +6,7 @@  #include <osmocom/core/linuxlist.h>  #include <stdbool.h> +#include <time.h>  /*! \defgroup select Select loop abstraction   *  @{ @@ -54,4 +55,10 @@ struct osmo_fd *osmo_fd_get_by_fd(int fd);  int osmo_fd_fill_fds(void *readset, void *writeset, void *exceptset);  int osmo_fd_disp_fds(void *readset, void *writeset, void *exceptset); +/* timerfd integration */ +int osmo_timerfd_disable(struct osmo_fd *ofd); +int osmo_timerfd_schedule(struct osmo_fd *ofd, const struct timespec *first, +			  const struct timespec *interval); +int osmo_timerfd_setup(struct osmo_fd *ofd, int (*cb)(struct osmo_fd *, unsigned int), void *data); +  /*! @} */ 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 */ | 
