return (isc_task_purgerange(task, sender, type, type, tag));
}
+/*
+ * The caller is responsible for freeing the event if this function returns
+ * true. If it returns false, then the event was already processed before it
+ * could be purged, so the event's action is responsible for freeing the event.
+ * The caller however must make sure that the event's destroy function, called
+ * when the event's action calls isc_event_destroy(), doesn't free the event
+ * while this function is still running. That is, 'event' must remain valid
+ * throughout the whole execution of this function.
+ */
bool
isc_task_purgeevent(isc_task_t *task, isc_event_t *event) {
bool found = false;
/*
* If 'event' is on the task's event queue, it will be purged,
* unless it is marked as unpurgeable. 'event' does not have to be
- * on the task's event queue; in fact, it can even be an invalid
- * pointer. Purging only occurs if the event is actually on the task's
- * event queue.
+ * on the task's event queue.
*
* Purging never changes the state of the task.
*/
return (false);
}
- isc_event_free(&event);
-
return (true);
}
while ((event = ISC_LIST_HEAD(timer->active)) != NULL) {
timerevent_unlink(timer, event);
+ bool purged = isc_task_purgeevent(timer->task,
+ (isc_event_t *)event);
UNLOCK(&timer->lock);
#if defined(UNIT_TESTING)
usleep(100);
#endif
- (void)isc_task_purgeevent(timer->task, (isc_event_t *)event);
+ if (purged) {
+ isc_event_free((isc_event_t **)&event);
+ } else {
+ /*
+ * The event was processed while we were trying to
+ * purge it. The event's action is responsible for
+ * calling isc_event_free(), which in turn will call
+ * event->ev_destroy() (timerevent_destroy() here),
+ * which will unlink and destroy it.
+ */
+ }
LOCK(&timer->lock);
}
}
purged = isc_task_purgeevent(task, event2_clone);
assert_int_equal(purgeable, purged);
+ if (purged) {
+ isc_event_free(&event2_clone);
+ }
/*
* Unblock the task, allowing event processing.