There was actually a bug in the original version of this: it tried to
run the finalizers after (potentially) setting current_base to NULL;
but those finalizers could themselves (potentially) be invoking stuff
that needed to know about the current event_base. So the right time to
do it is _before_ clearing current_base.
When resuming the system from a suspended state, the ev_timeout field
of a scheduled timer event may be in the past. This leads to
unexpected behavior when scheduling a short-duration timer event
immediately after returning from suspension, because the new event
does not land on top of the timeout minheap and so the event loop
(blocked on a possibly long-duration timeout) is not notified.
This patch checks for this condition and, if it obtains, notifies the
event loop.
* Fix whitespace
* Explain return value from callback function
* Reinstate return value so that caller can tell whether forech
exited early.
* Rename event_base_foreach_event_() to
event_base_foreach_event_nolock_().
* Use event_base_foreach_event_cb_fn typedef in more places
* Be more dire about undefined behavior.
This is necessary for making some thread libraries work with
event.c, and might get better performance with others.
The biggest change required here was that we needed to make some
internal code that had previously called event_add and event_del
call the nolock variants.
Back when deferred_cb stuff had its own queue, the queue was always
executed, but we never ran more than 16 callbacks per iteration.
That made for two problems:
1: Because deferred_cb stuff would always run, and had no priority,
it could cause priority inversion.
2: It doesn't respect the max_dispatch_interval code.
Then, when I refactored deferred_cb to be a special case of
event_callback, that solved the above issues, but made for two more
issues:
3: Because deferred_cb stuff would always get the default priority,
it could could low-priority bufferevents to get too much priority.
4: With code like bufferevent_pair, it's easy to get into a
situation where two deferreds keep adding one another, preventing
the event loop from ever actually scanning for more events.
This commit fixes the above by giving deferreds a better notion of
priorities, and by limiting the number of deferreds that can be
added to the _current_ loop iteration's active queues. (Extra
deferreds are put into the active_later state.)
That isn't an all-purpose priority inversion solution, of course: for
that, you may need to mess around with max_dispatch_interval.
An event or event callback can now be in an additional state: "active
later". When an event is in this state, it will become active the
next time we run through the event loop. This lets us do what we
wanted to with deferred callbacks: make a type of active thing that
avoids infinite circular regress in a way that starves other events or
exhausts the stack. It improves on deferred callbacks by respecting
priorities, and by having a non-kludgy way to avoid event starvation.
This shouldn't have any visible effect, but it's necessary or
advisible for a few changes and cleanups I would like to make,
including:
* Replacing the deferred queue with a type that works more as if it
were an event.
* Introducing a useful "activate this on the next round through the
event loop" state for events and deferreds.
* Adding an "on until further notice" status for events, to allow a
saner win32-hybrid approach.
* Eventually, making all user callbacks first-class things with
event-like semantics.
Fixes an issue reported on libevent-users in the thread "a dead
looping bug when changing system time backward". Previously, if time
jumped forward 1 hour[*] and we had a one-second periodic timer event,
that event would get invoked 3600 times. That's almost certainly not
what anybody wants.
In a future version of Libevent, we should expose the amount of time
that the callbac kwould have been invoked somehow.
[*] Forward time jumps can happen with nonmonotonic clocks, or with
clocks that jump on suspend/resume. It can also happen from
Libevent's point of view if the user exits from event_base_loop() and
doesn't call it again for a while.
The use_monotonic field used to be a static field set up at library
setup. Unfortunately, this makes it hard to give the user a way to
make speed/accuracy tradeoffs about time. Moving it into event_base
should let the clock implementation become configurable.
Sufficiently recent kqueue implementations have an EVFILT_USER filter
that we can use to wake up an event base from another thread. When
it's supported, we now use this mechanism rather than our old
(pipe-based) mechanism. This should save some time and complications
on newer OSX and freebsds.
Apparently, now that we have tests for it in main/common_timeout, we
can now see that it sometimes breaks referential integrity somehow.
Since I'd like to get 2.1.1-alpha out the door soon, I'm turning it
off for now.