| /* libnih |
| * |
| * timer.c - timeouts, periodic and scheduled timers |
| * |
| * Copyright © 2009 Scott James Remnant <scott@netsplit.com>. |
| * Copyright © 2009 Canonical Ltd. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining |
| * a copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sublicense, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be |
| * included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR |
| * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
| * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| # include <config.h> |
| #endif /* HAVE_CONFIG_H */ |
| |
| |
| #include <time.h> |
| #include <string.h> |
| |
| #include <nih/macros.h> |
| #include <nih/alloc.h> |
| #include <nih/list.h> |
| #include <nih/logging.h> |
| #include <nih/error.h> |
| |
| #include "timer.h" |
| |
| |
| /** |
| * nih_timers: |
| * |
| * This is the list of all registered timers, it is not sorted into any |
| * particular order. The due time of timers should be set when the timer |
| * is added to this list, or rescheduled; it is not calculated on the fly. |
| * |
| * Each item is an NihTimer structure. |
| **/ |
| NihList *nih_timers = NULL; |
| |
| |
| /** |
| * nih_timer_init: |
| * |
| * Initialise the timer list. |
| **/ |
| void |
| nih_timer_init (void) |
| { |
| if (! nih_timers) |
| nih_timers = NIH_MUST (nih_list_new (NULL)); |
| } |
| |
| |
| /** |
| * nih_timer_add_timeout: |
| * @parent: parent object for new timer, |
| * @timeout: seconds to wait before triggering, |
| * @callback: function to be called, |
| * @data: pointer to pass to function as first argument. |
| * |
| * Arranges for the @callback function to be called in @timeout seconds |
| * time, or the soonest period thereafter. A timer may be called |
| * immediately by passing zero or a non-negative number as @timeout. |
| * |
| * The timer structure is allocated using nih_alloc() and stored in |
| * a linked list; there is no non-allocated version of this function |
| * because of this and because it will be automatically freed once called. |
| * |
| * Cancellation of the timer can be performed by freeing it. |
| * |
| * If @parent is not NULL, it should be a pointer to another object which |
| * will be used as a parent for the returned timer. When all parents |
| * of the returned timer are freed, the returned timer will also be |
| * freed. |
| * |
| * Returns: the new timer information, or NULL if insufficient memory. |
| **/ |
| NihTimer * |
| nih_timer_add_timeout (const void *parent, |
| time_t timeout, |
| NihTimerCb callback, |
| void *data) |
| { |
| NihTimer *timer; |
| |
| nih_assert (callback != NULL); |
| |
| nih_timer_init (); |
| |
| timer = nih_new (parent, NihTimer); |
| if (! timer) |
| return NULL; |
| |
| nih_list_init (&timer->entry); |
| |
| nih_alloc_set_destructor (timer, nih_list_destroy); |
| |
| timer->type = NIH_TIMER_TIMEOUT; |
| timer->timeout = timeout; |
| |
| timer->callback = callback; |
| timer->data = data; |
| |
| timer->due = time (NULL) + timeout; |
| |
| nih_list_add (nih_timers, &timer->entry); |
| |
| return timer; |
| } |
| |
| /** |
| * nih_timer_add_periodic: |
| * @parent: parent object for new timer, |
| * @period: number of seconds between calls, |
| * @callback: function to be called, |
| * @data: pointer to pass to function as first argument. |
| * |
| * Arranges for the @callback function to be called every @period seconds, |
| * or the soonest time thereafter. |
| * |
| * The timer structure is allocated using nih_alloc() and stored in |
| * a linked list; there is no non-allocated version of this function |
| * because of this. |
| * |
| * Cancellation of the timer can be performed by freeing it. |
| * |
| * If @parent is not NULL, it should be a pointer to another object which |
| * will be used as a parent for the returned timer. When all parents |
| * of the returned timer are freed, the returned timer will also be |
| * freed. |
| * |
| * Returns: the new timer information, or NULL if insufficient memory. |
| **/ |
| NihTimer * |
| nih_timer_add_periodic (const void *parent, |
| time_t period, |
| NihTimerCb callback, |
| void *data) |
| { |
| NihTimer *timer; |
| |
| nih_assert (callback != NULL); |
| nih_assert (period > 0); |
| |
| nih_timer_init (); |
| |
| timer = nih_new (parent, NihTimer); |
| if (! timer) |
| return NULL; |
| |
| nih_list_init (&timer->entry); |
| |
| nih_alloc_set_destructor (timer, nih_list_destroy); |
| |
| timer->type = NIH_TIMER_PERIODIC; |
| timer->period = period; |
| |
| timer->callback = callback; |
| timer->data = data; |
| |
| timer->due = time (NULL) + period; |
| |
| nih_list_add (nih_timers, &timer->entry); |
| |
| return timer; |
| } |
| |
| /** |
| * nih_timer_add_scheduled: |
| * @parent: parent object for new timer, |
| * @schedule: trigger schedule, |
| * @callback: function to be called, |
| * @data: pointer to pass to function as first argument. |
| * |
| * Arranges for the @callback function to be called based on the @schedule |
| * given. |
| * |
| * The timer structure is allocated using nih_alloc() and stored in |
| * a linked list; there is no non-allocated version of this function |
| * because of this. |
| * |
| * Cancellation of the timer can be performed by freeing it. |
| * |
| * If @parent is not NULL, it should be a pointer to another object which |
| * will be used as a parent for the returned timer. When all parents |
| * of the returned timer are freed, the returned timer will also be |
| * freed. |
| * |
| * Returns: the new timer information, or NULL if insufficient memory. |
| **/ |
| NihTimer * |
| nih_timer_add_scheduled (const void *parent, |
| NihTimerSchedule *schedule, |
| NihTimerCb callback, |
| void *data) |
| { |
| NihTimer *timer; |
| |
| nih_assert (callback != NULL); |
| nih_assert (schedule != NULL); |
| |
| nih_timer_init (); |
| |
| timer = nih_new (parent, NihTimer); |
| if (! timer) |
| return NULL; |
| |
| nih_list_init (&timer->entry); |
| |
| nih_alloc_set_destructor (timer, nih_list_destroy); |
| |
| timer->type = NIH_TIMER_SCHEDULED; |
| memcpy (&timer->schedule, schedule, sizeof (NihTimerSchedule)); |
| |
| timer->callback = callback; |
| timer->data = data; |
| |
| /* FIXME Not implemented */ |
| timer->due = 0; |
| |
| nih_list_add (nih_timers, &timer->entry); |
| |
| return timer; |
| } |
| |
| |
| /** |
| * nih_timer_next_due: |
| * |
| * Iterates the complete list of timers looking for the one with the |
| * lowest due time, so that the timer returned is either due to be triggered |
| * now or in some period's time. |
| * |
| * Normally used to determine how long we can sleep for by subtracting the |
| * current time from the due time of the next timer. |
| * |
| * Returns: next timer due, or NULL if there are no timers. |
| **/ |
| NihTimer * |
| nih_timer_next_due (void) |
| { |
| NihTimer *next; |
| |
| nih_timer_init (); |
| |
| next = NULL; |
| NIH_LIST_FOREACH (nih_timers, iter) { |
| NihTimer *timer = (NihTimer *)iter; |
| |
| if ((next == NULL) || (timer->due < next->due)) |
| next = timer; |
| } |
| |
| return next; |
| } |
| |
| |
| /** |
| * nih_timer_poll: |
| * |
| * Iterates the complete list of timers and triggers any for which the |
| * due time is less than or equal to the current time by calling their |
| * callback functions. |
| * |
| * Arranges for the timer to be rescheuled, unless it is a timeout in which |
| * case it is removed from the timer list. |
| **/ |
| void |
| nih_timer_poll (void) |
| { |
| time_t now; |
| |
| nih_timer_init (); |
| |
| now = time (NULL); |
| NIH_LIST_FOREACH_SAFE (nih_timers, iter) { |
| NihTimer *timer = (NihTimer *)iter; |
| int free_when_done = FALSE; |
| |
| if (timer->due > now) |
| continue; |
| |
| switch (timer->type) { |
| case NIH_TIMER_TIMEOUT: |
| nih_ref (timer, nih_timers); |
| free_when_done = TRUE; |
| break; |
| case NIH_TIMER_PERIODIC: |
| timer->due = now + timer->period; |
| break; |
| case NIH_TIMER_SCHEDULED: |
| /* FIXME Not implemented */ |
| timer->due = 0; |
| break; |
| } |
| |
| nih_error_push_context (); |
| timer->callback (timer->data, timer); |
| nih_error_pop_context (); |
| |
| if (free_when_done) |
| nih_free (timer); |
| } |
| } |