Fix crash when timeout is removed from its handler

Remove the timeout before dispatching the handler, and allow
calling SCH_RemoveTimeout() with nonexistent id.
This commit is contained in:
Miroslav Lichvar 2010-12-17 14:52:39 +01:00
parent 30c038c3c3
commit 1d6b94b458

27
sched.c
View file

@ -395,12 +395,9 @@ void
SCH_RemoveTimeout(SCH_TimeoutID id) SCH_RemoveTimeout(SCH_TimeoutID id)
{ {
TimerQueueEntry *ptr; TimerQueueEntry *ptr;
int ok;
assert(initialised); assert(initialised);
ok = 0;
for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) { for (ptr = timer_queue.next; ptr != &timer_queue; ptr = ptr->next) {
if (ptr->id == id) { if (ptr->id == id) {
@ -416,14 +413,9 @@ SCH_RemoveTimeout(SCH_TimeoutID id)
/* Release memory back to the operating system */ /* Release memory back to the operating system */
release_tqe(ptr); release_tqe(ptr);
ok = 1;
break; break;
} }
} }
assert(ok);
} }
/* ================================================== */ /* ================================================== */
@ -433,27 +425,24 @@ SCH_RemoveTimeout(SCH_TimeoutID id)
static int static int
dispatch_timeouts(struct timeval *now) { dispatch_timeouts(struct timeval *now) {
TimerQueueEntry *ptr; TimerQueueEntry *ptr;
SCH_TimeoutHandler handler;
SCH_ArbitraryArgument arg;
int n_done = 0; int n_done = 0;
if ((n_timer_queue_entries > 0) && if ((n_timer_queue_entries > 0) &&
(UTI_CompareTimevals(now, &(timer_queue.next->tv)) >= 0)) { (UTI_CompareTimevals(now, &(timer_queue.next->tv)) >= 0)) {
ptr = timer_queue.next; ptr = timer_queue.next;
handler = ptr->handler;
arg = ptr->arg;
SCH_RemoveTimeout(ptr->id);
/* Dispatch the handler */ /* Dispatch the handler */
(ptr->handler)(ptr->arg); (handler)(arg);
/* Increment count of timeouts handled */ /* Increment count of timeouts handled */
++n_done; ++n_done;
/* Unlink entry from the queue */
ptr->prev->next = ptr->next;
ptr->next->prev = ptr->prev;
/* Decrement count of entries in queue */
--n_timer_queue_entries;
/* Delete entry */
release_tqe(ptr);
} }
return n_done; return n_done;