summaryrefslogtreecommitdiffstats
path: root/lib/qtimers.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/qtimers.c')
-rw-r--r--lib/qtimers.c180
1 files changed, 110 insertions, 70 deletions
diff --git a/lib/qtimers.c b/lib/qtimers.c
index 508fc7d7..8c08a6bc 100644
--- a/lib/qtimers.c
+++ b/lib/qtimers.c
@@ -81,8 +81,11 @@ enum { qdebug =
* timer (which may, or may not, be the current qtimer time).
*
* During an action function timers may be set/unset, actions changed, and so
- * on... there are no restrictions EXCEPT that the qtimer structure may NOT be
- * freed.
+ * on... there are no restrictions EXCEPT that may NOT recurse into the
+ * dispatch function.
+ *
+ * If nothing is done with the time during the action function, the timer is
+ * implicitly unset when the action function returns.
*/
static int
@@ -99,7 +102,8 @@ qtimer_cmp(qtimer* a, qtimer* b) /* the heap discipline */
* qtimer_pile handling
*/
-/* Initialise a timer pile -- allocating it if required.
+/*------------------------------------------------------------------------------
+ * Initialise a timer pile -- allocating it if required.
*
* Returns the qtimer_pile.
*/
@@ -114,6 +118,7 @@ qtimer_pile_init_new(qtimer_pile qtp)
/* Zeroising has initialised:
*
* timers -- invalid heap -- need to properly initialise
+ * current = NULL -- no current timer
*/
/* (The typedef is required to stop Eclipse (3.4.2 with CDT 5.0) whining
@@ -126,13 +131,14 @@ qtimer_pile_init_new(qtimer_pile qtp)
return qtp ;
} ;
-/* Get the timer time for the first timer due to go off in the given pile.
+/*------------------------------------------------------------------------------
+ * Get the timer time for the first timer due to go off in the given pile.
*
* The caller must provide a maximum acceptable time. If the qtimer pile is
* empty, or the top entry times out after the maximum time, then the maximum
* is returned.
*/
-qtime_t
+extern qtime_t
qtimer_pile_top_wait(qtimer_pile qtp, qtime_t max_wait)
{
qtime_t top_wait ;
@@ -146,7 +152,8 @@ qtimer_pile_top_wait(qtimer_pile qtp, qtime_t max_wait)
return (top_wait < max_wait) ? top_wait : max_wait ;
} ;
-/* Dispatch the next timer whose time is <= the given "upto" time.
+/*------------------------------------------------------------------------------
+ * Dispatch the next timer whose time is <= the given "upto" time.
*
* The upto time must be a qtimer time (!) -- see qtimer_time_now().
*
@@ -155,8 +162,10 @@ qtimer_pile_top_wait(qtimer_pile qtp, qtime_t max_wait)
*
* Returns true <=> dispatched a timer, and there may be more to do.
* false <=> nothing to do (and nothing done).
+ *
+ * NB: it is a sad, very sad, mistake to recurse into this !
*/
-int
+extern bool
qtimer_pile_dispatch_next(qtimer_pile qtp, qtime_mono_t upto)
{
qtimer qtr ;
@@ -165,23 +174,26 @@ qtimer_pile_dispatch_next(qtimer_pile qtp, qtime_mono_t upto)
qtimer_pile_verify(qtp) ;
qtr = heap_top_item(&qtp->timers) ;
- if ((qtr != NULL) && (qtr->time <= upto))
- {
- passert(qtp == qtr->pile);
- qtr->state = qtr_state_unset_pending ;
- qtr->action(qtr, qtr->timer_info, upto) ;
+ if ((qtr == NULL) || (qtr->time > upto))
+ return 0 ;
- if (qtr->state == qtr_state_unset_pending)
- qtimer_unset(qtr) ;
+ passert((qtp == qtr->pile) && (qtr->active)) ;
- return 1 ;
- }
+ qtp->implicit_unset = qtr ; /* Timer must be unset if is still here
+ when the action function returns */
+ qtr->action(qtr, qtr->timer_info, upto) ;
+
+ if (qtp->implicit_unset == qtr)
+ qtimer_unset(qtr) ;
else
- return 0 ;
+ assert(qtp->implicit_unset == NULL) ; /* check for tidy-ness */
+
+ return 1 ;
} ;
-/* Ream out (another) item from qtimer_pile.
+/*------------------------------------------------------------------------------
+ * Ream out (another) item from qtimer_pile.
*
* If pile is empty, release the qtimer_pile structure, if required.
*
@@ -207,7 +219,7 @@ qtimer_pile_ream(qtimer_pile qtp, int free_structure)
qtr = heap_ream_keep(&qtp->timers) ; /* ream, keeping the heap structure */
if (qtr != NULL)
- qtr->state = qtr_state_inactive ; /* has been removed from pile */
+ qtr->active = false ; /* has been removed from pile */
else
if (free_structure) /* pile is empty, may now free it */
XFREE(MTYPE_QTIMER_PILE, qtp) ;
@@ -219,7 +231,8 @@ qtimer_pile_ream(qtimer_pile qtp, int free_structure)
* qtimer handling
*/
-/* Initialise qtimer structure -- allocating one if required.
+/*------------------------------------------------------------------------------
+ * Initialise qtimer structure -- allocating one if required.
*
* Associates qtimer with the given pile of timers, and sets up the action and
* the timer_info.
@@ -242,7 +255,7 @@ qtimer_init_new(qtimer qtr, qtimer_pile qtp,
* pile -- NULL -- not in any pile (yet)
* backlink -- unset
*
- * state -- not active
+ * active -- false
*
* time -- unset
* action -- NULL -- no action set (yet)
@@ -251,8 +264,6 @@ qtimer_init_new(qtimer qtr, qtimer_pile qtp,
* interval -- unset
*/
- confirm(qtr_state_inactive == 0) ;
-
qtr->pile = qtp ;
qtr->action = action ;
qtr->timer_info = timer_info ;
@@ -260,53 +271,54 @@ qtimer_init_new(qtimer qtr, qtimer_pile qtp,
return qtr ;
} ;
-/* Free given timer.
+/*------------------------------------------------------------------------------
+ * Free given timer -- if any.
*
- * Unsets it first if it is active.
+ * Unsets it first if it is active or pending unset.
*
- * The timer MAY NOT be currently the subject of qtimer_pile_dispatch_next().
+ * Returns: NULL
*/
-void
+extern qtimer
qtimer_free(qtimer qtr)
{
- assert(qtr->state != qtr_state_unset_pending) ;
+ /* Note that if is the current dispatched timer and an unset is still
+ * pending, then it must still be active.
+ */
+ if (qtr != NULL)
+ {
+ if (qtr->active)
+ qtimer_unset(qtr) ;
- if (qtr->state != qtr_state_inactive)
- qtimer_unset(qtr) ;
+ XFREE(MTYPE_QTIMER, qtr) ;
+ } ;
- XFREE(MTYPE_QTIMER, qtr) ;
+ return NULL ;
} ;
-/* Set pile in which given timer belongs.
+/*------------------------------------------------------------------------------
+ * Set pile in which given timer belongs.
+ *
+ * Does nothing if timer already belongs to the given pile.
*
- * Unsets the timer if active in another pile.
- * (Does nothing if active in the "new" pile.)
+ * Unsets the timer if active in another pile, before reassigning it.
*/
-void
+extern void
qtimer_set_pile(qtimer qtr, qtimer_pile qtp)
{
- if (qtr_is_active(qtr) && (qtr->pile != qtp))
+ if (qtr->pile == qtp)
+ return ;
+
+ /* Note that if is the current dispatched timer and an unset is still
+ * pending, then it must still be active.
+ */
+ if (qtr->active)
qtimer_unset(qtr) ;
+
qtr->pile = qtp ;
}
-/* Set action for given timer.
- */
-void
-qtimer_set_action(qtimer qtr, qtimer_action* action)
-{
- qtr->action = action ;
-} ;
-
-/* Set timer_info for given timer.
- */
-void
-qtimer_set_info(qtimer qtr, void* timer_info)
-{
- qtr->timer_info = timer_info ;
-} ;
-
-/* Set given timer.
+/*------------------------------------------------------------------------------
+ * Set given timer.
*
* Setting a -ve time => qtimer_unset.
*
@@ -319,7 +331,7 @@ qtimer_set_info(qtimer qtr, void* timer_info)
*
* It is an error to set a timer which has a NULL action.
*/
-void
+extern void
qtimer_set(qtimer qtr, qtime_mono_t when, qtimer_action* action)
{
qtimer_pile qtp ;
@@ -328,20 +340,30 @@ qtimer_set(qtimer qtr, qtime_mono_t when, qtimer_action* action)
return qtimer_unset(qtr) ;
qtp = qtr->pile ;
- dassert(qtp != NULL) ;
+ assert(qtp != NULL) ;
+
if (qdebug)
qtimer_pile_verify(qtp) ;
qtr->time = when ;
- if (qtr_is_active(qtr))
- heap_update_item(&qtp->timers, qtr) ; /* update in heap */
+ if (qtr->active)
+ {
+ /* Is active, so update the timer in the pile. */
+ heap_update_item(&qtp->timers, qtr) ;
+
+ if (qtr == qtp->implicit_unset)
+ qtp->implicit_unset = NULL ; /* no unset required, now */
+ }
else
- heap_push_item(&qtp->timers, qtr) ; /* add to heap */
+ {
+ /* Is not active, so insert the timer into the pile. */
+ heap_push_item(&qtp->timers, qtr) ;
- assert(qtp == qtr->pile);
+ assert(qtr != qtp->implicit_unset) ; /* because it's not active */
- qtr->state = qtr_state_active ; /* overrides any unset pending */
+ qtr->active = true ;
+ } ;
if (action != NULL)
qtr->action = action ;
@@ -352,28 +374,35 @@ qtimer_set(qtimer qtr, qtime_mono_t when, qtimer_action* action)
qtimer_pile_verify(qtp) ;
} ;
-/* Unset given timer
+/*------------------------------------------------------------------------------
+ * Unset given timer
*
* If the timer is active, removes from pile and sets inactive.
*/
-void
+extern void
qtimer_unset(qtimer qtr)
{
- if (qtr_is_active(qtr))
- {
- qtimer_pile qtp = qtr->pile ;
- dassert(qtp != NULL) ;
+ qtimer_pile qtp = qtr->pile ;
- if (qdebug)
- qtimer_pile_verify(qtp) ;
+ assert(qtp != NULL) ;
+
+ if (qdebug)
+ qtimer_pile_verify(qtp) ;
+
+ if (qtr->active)
+ {
+ if (qtr == qtp->implicit_unset)
+ qtp->implicit_unset = NULL ; /* no unset required, now */
heap_delete_item(&qtp->timers, qtr) ;
if (qdebug)
qtimer_pile_verify(qtp) ;
- qtr->state = qtr_state_inactive ; /* overrides any unset pending */
- } ;
+ qtr->active = false ;
+ }
+ else
+ assert(qtr != qtp->implicit_unset) ;
} ;
/*==============================================================================
@@ -387,6 +416,9 @@ qtimer_pile_verify(qtimer_pile qtp)
vector_index i ;
vector_index e ;
qtimer qtr ;
+ bool seen ;
+
+ assert(qtp != NULL) ;
/* (The typedef is required to stop Eclipse (3.4.2 with CDT 5.0) whining
* about first argument of offsetof().)
@@ -402,9 +434,17 @@ qtimer_pile_verify(qtimer_pile qtp)
for (i = 0 ; i < e ; ++i)
{
qtr = vector_get_item(v, i) ;
+ assert(qtr != NULL) ;
+
+ if (qtr == qtp->implicit_unset)
+ seen = 1 ;
+
+ assert(qtr->active) ;
assert(qtr->pile == qtp) ;
assert(qtr->backlink == i) ;
assert(qtr->action != NULL) ;
} ;
+
+ assert(seen || (qtp->implicit_unset == NULL)) ;
} ;