From dce2366b3a7a74986048f507afba1a2063e4e014 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Thu, 23 Jun 2011 13:47:55 +0200 Subject: [PATCH] Detect infinite loop in scheduler If more timeouts were handled than there were in the timer queue on start, assume some code is scheduling timeouts with negative delays and abort. Make the actual limit higher in case the machine is temporarily overloaded and dispatching the handlers takes more time than was delay of a scheduled timeout. --- sched.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/sched.c b/sched.c index 9545212..d7c5c38 100644 --- a/sched.c +++ b/sched.c @@ -430,18 +430,26 @@ SCH_RemoveTimeout(SCH_TimeoutID id) } /* ================================================== */ -/* The current time (now) has to be passed in from the - caller to avoid race conditions */ +/* Try to dispatch any timeouts that have already gone by, and + keep going until all are done. (The earlier ones may take so + long to do that the later ones come around by the time they are + completed). */ -static int +static void dispatch_timeouts(struct timeval *now) { TimerQueueEntry *ptr; SCH_TimeoutHandler handler; SCH_ArbitraryArgument arg; - int n_done = 0; + int n_done = 0, n_entries_on_start = n_timer_queue_entries; + + while (1) { + LCL_ReadRawTime(now); + + if (!(n_timer_queue_entries > 0 && + UTI_CompareTimevals(now, &(timer_queue.next->tv)) >= 0)) { + break; + } - if ((n_timer_queue_entries > 0) && - (UTI_CompareTimevals(now, &(timer_queue.next->tv)) >= 0)) { ptr = timer_queue.next; last_class_dispatch[ptr->class] = *now; @@ -456,10 +464,16 @@ dispatch_timeouts(struct timeval *now) { /* Increment count of timeouts handled */ ++n_done; + + /* If more timeouts were handled than there were in the timer queue on + start, assume some code is scheduling timeouts with negative delays and + abort. Make the actual limit higher in case the machine is temporarily + overloaded and dispatching the handlers takes more time than was delay + of a scheduled timeout. */ + if (n_done > n_entries_on_start * 4) { + LOG_FATAL(LOGF_Scheduler, "Possible infinite loop in scheduling"); + } } - - return n_done; - } /* ================================================== */ @@ -562,20 +576,15 @@ SCH_MainLoop(void) /* Copy current set of read file descriptors */ memcpy((void *) &rd, (void *) &read_fds, sizeof(fd_set)); - /* Try to dispatch any timeouts that have already gone by, and - keep going until all are done. (The earlier ones may take so - long to do that the later ones come around by the time they are - completed). */ - - do { - LCL_ReadRawTime(&now); - } while (dispatch_timeouts(&now) > 0); + /* Dispatch timeouts and fill now with current raw time */ + dispatch_timeouts(&now); /* Check whether there is a timeout and set it up */ if (n_timer_queue_entries > 0) { UTI_DiffTimevals(&tv, &(timer_queue.next->tv), &now); ptv = &tv; + assert(tv.tv_sec > 0 || tv.tv_usec > 0); } else { ptv = NULL;