| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- /*
- *
- * Embedded Linux library
- *
- * Copyright (C) 2011-2014 Intel Corporation. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #define _GNU_SOURCE
- #include <errno.h>
- #include <unistd.h>
- #include <stdbool.h>
- #include <string.h>
- #include <sys/epoll.h>
- #include <sys/timerfd.h>
- #include <time.h>
- #include <limits.h>
- #include "useful.h"
- #include "timeout.h"
- #include "main-private.h"
- #include "private.h"
- /**
- * SECTION:timeout
- * @short_description: Timeout support
- *
- * Timeout support
- */
- /**
- * l_timeout:
- *
- * Opague object representing the timeout.
- */
- struct l_timeout {
- int fd;
- l_timeout_notify_cb_t callback;
- l_timeout_destroy_cb_t destroy;
- void *user_data;
- };
- static void timeout_destroy(void *user_data)
- {
- struct l_timeout *timeout = user_data;
- close(timeout->fd);
- timeout->fd = -1;
- if (timeout->destroy)
- timeout->destroy(timeout->user_data);
- }
- static void timeout_callback(int fd, uint32_t events, void *user_data)
- {
- struct l_timeout *timeout = user_data;
- uint64_t expired;
- ssize_t result;
- result = read(timeout->fd, &expired, sizeof(expired));
- if (result != sizeof(expired))
- return;
- if (timeout->callback)
- timeout->callback(timeout, timeout->user_data);
- }
- static inline int timeout_set(int fd, unsigned int seconds, long nanoseconds)
- {
- struct itimerspec itimer;
- memset(&itimer, 0, sizeof(itimer));
- itimer.it_interval.tv_sec = 0;
- itimer.it_interval.tv_nsec = 0;
- itimer.it_value.tv_sec = seconds;
- itimer.it_value.tv_nsec = nanoseconds;
- return timerfd_settime(fd, 0, &itimer, NULL);
- }
- static bool convert_ms(uint64_t milliseconds, unsigned int *seconds,
- long *nanoseconds)
- {
- uint64_t big_seconds = milliseconds / 1000;
- if (big_seconds > UINT_MAX)
- return false;
- *seconds = big_seconds;
- *nanoseconds = (milliseconds % 1000) * 1000000L;
- return true;
- }
- /**
- * timeout_create_with_nanoseconds:
- * @seconds: number of seconds
- * @nanoseconds: number of nanoseconds
- * @callback: timeout callback function
- * @user_data: user data provided to timeout callback function
- * @destroy: destroy function for user data
- *
- * Create new timeout callback handling.
- *
- * The timeout will only fire once. The timeout handling needs to be rearmed
- * with one of the l_timeout_modify functions to trigger again.
- *
- * Returns: a newly allocated #l_timeout object. On failure, the function
- * returns NULL.
- **/
- static struct l_timeout *timeout_create_with_nanoseconds(unsigned int seconds,
- long nanoseconds, l_timeout_notify_cb_t callback,
- void *user_data, l_timeout_destroy_cb_t destroy)
- {
- struct l_timeout *timeout;
- int err;
- if (unlikely(!callback))
- return NULL;
- timeout = l_new(struct l_timeout, 1);
- timeout->callback = callback;
- timeout->destroy = destroy;
- timeout->user_data = user_data;
- timeout->fd = timerfd_create(CLOCK_MONOTONIC,
- TFD_NONBLOCK | TFD_CLOEXEC);
- if (timeout->fd < 0) {
- l_free(timeout);
- return NULL;
- }
- if (seconds > 0 || nanoseconds > 0) {
- if (timeout_set(timeout->fd, seconds, nanoseconds) < 0) {
- close(timeout->fd);
- l_free(timeout);
- return NULL;
- }
- }
- err = watch_add(timeout->fd, EPOLLIN | EPOLLONESHOT, timeout_callback,
- timeout, timeout_destroy);
- if (err < 0) {
- l_free(timeout);
- return NULL;
- }
- return timeout;
- }
- /**
- * l_timeout_create:
- * @seconds: timeout in seconds
- * @callback: timeout callback function
- * @user_data: user data provided to timeout callback function
- * @destroy: destroy function for user data
- *
- * Create new timeout callback handling.
- *
- * The timeout will only fire once. The timeout handling needs to be rearmed
- * with one of the l_timeout_modify functions to trigger again.
- *
- * Returns: a newly allocated #l_timeout object. On failure, the function
- * returns NULL.
- **/
- LIB_EXPORT struct l_timeout *l_timeout_create(unsigned int seconds,
- l_timeout_notify_cb_t callback,
- void *user_data, l_timeout_destroy_cb_t destroy)
- {
- return timeout_create_with_nanoseconds(seconds, 0, callback,
- user_data, destroy);
- }
- /**
- * l_timeout_create_ms:
- * @milliseconds: timeout in milliseconds
- * @callback: timeout callback function
- * @user_data: user data provided to timeout callback function
- * @destroy: destroy function for user data
- *
- * Create new timeout callback handling.
- *
- * The timeout will only fire once. The timeout handling needs to be rearmed
- * with one of the l_timeout_modify functions to trigger again.
- *
- * Returns: a newly allocated #l_timeout object. On failure, the function
- * returns NULL.
- **/
- LIB_EXPORT struct l_timeout *l_timeout_create_ms(uint64_t milliseconds,
- l_timeout_notify_cb_t callback,
- void *user_data, l_timeout_destroy_cb_t destroy)
- {
- unsigned int seconds;
- long nanoseconds;
- if (!convert_ms(milliseconds, &seconds, &nanoseconds))
- return NULL;
- return timeout_create_with_nanoseconds(seconds, nanoseconds, callback,
- user_data, destroy);
- }
- /**
- * l_timeout_modify:
- * @timeout: timeout object
- * @seconds: timeout in seconds
- *
- * Modify an existing @timeout and rearm it.
- **/
- LIB_EXPORT void l_timeout_modify(struct l_timeout *timeout,
- unsigned int seconds)
- {
- if (unlikely(!timeout))
- return;
- if (unlikely(timeout->fd < 0))
- return;
- if (seconds > 0) {
- if (timeout_set(timeout->fd, seconds, 0) < 0)
- return;
- }
- watch_modify(timeout->fd, EPOLLIN | EPOLLONESHOT, true);
- }
- /**
- * l_timeout_modify_ms:
- * @timeout: timeout object
- * @milliseconds: number of milliseconds
- *
- * Modify an existing @timeout and rearm it.
- **/
- LIB_EXPORT void l_timeout_modify_ms(struct l_timeout *timeout,
- uint64_t milliseconds)
- {
- if (unlikely(!timeout))
- return;
- if (unlikely(timeout->fd < 0))
- return;
- if (milliseconds > 0) {
- unsigned int sec;
- long nanosec;
- if (!convert_ms(milliseconds, &sec, &nanosec) ||
- timeout_set(timeout->fd, sec, nanosec) < 0)
- return;
- }
- watch_modify(timeout->fd, EPOLLIN | EPOLLONESHOT, true);
- }
- /**
- * l_timeout_remove:
- * @timeout: timeout object
- *
- * Remove timeout handling.
- **/
- LIB_EXPORT void l_timeout_remove(struct l_timeout *timeout)
- {
- if (unlikely(!timeout))
- return;
- watch_remove(timeout->fd, false);
- l_free(timeout);
- }
- /**
- * l_timeout_set_callback:
- * @timeout: timeout object
- * @callback: The new callback
- * @user_data: The new user_data
- * @destroy: The new destroy function
- *
- * Sets the new notify callback for @timeout. If the old user_data object had
- * a destroy function set, then that function will be called.
- */
- LIB_EXPORT void l_timeout_set_callback(struct l_timeout *timeout,
- l_timeout_notify_cb_t callback,
- void *user_data,
- l_timeout_destroy_cb_t destroy)
- {
- if (unlikely(!timeout))
- return;
- if (timeout->destroy)
- timeout->destroy(timeout->user_data);
- timeout->callback = callback;
- timeout->user_data = user_data;
- timeout->destroy = destroy;
- }
|