I recently hit an infinite loop in timeout_process for the following loop:
while ((ev = min_heap_top(&base->timeheap))) {
if (evutil_timercmp(&ev->ev_timeout, &now, >))
break;
/* delete this event from the I/O queues */
event_del_internal(ev);
event_debug(("timeout_process: call %p",
ev->ev_callback));
event_active_nolock(ev, EV_TIMEOUT, 1);
}
The problem was that the specific event at top of min_heap was missing EVLIST_TIMEOUT flag. Therefore it's not removed from event_del_internal(). After more debugging we found the root cause - a threading issue on our side (not in libevent) - that caused problem with the min_heap and resulted in this inconsistent state.
That said, I think this code can be improved to handle this inconsistent state better. Infinite loops are hard to detect and debug. Instead of relying on event_del_internal() to remove it from the min_heap list, it can be popped out directly from here. i.e.:
while ((ev = min_heap_top(&base->timeheap))) {
if (evutil_timercmp(&ev->ev_timeout, &now, >))
break;
/* pop it from the heap */
min_heap_pop(&base->timeheap);
ev->ev_flags &= ~EVLIST_TIMEOUT;
/* delete this event from the I/O queues */
event_del_internal(ev);
event_debug(("timeout_process: call %p",
ev->ev_callback));
event_active_nolock(ev, EV_TIMEOUT, 1);
}
It is also slightly more performant since min_heap_pop() does less checks than min_heap_erase().
Thanks,
Naizhi