diff options
author | Zac Medico <zmedico@gentoo.org> | 2017-05-05 02:07:38 -0700 |
---|---|---|
committer | Zac Medico <zmedico@gentoo.org> | 2017-05-05 11:32:45 -0700 |
commit | dac5089eb7908e9fd643f46c913515082077281e (patch) | |
tree | 229627945cc3033eb2c7f596754b0a1aa8a98c4a | |
parent | man/emerge.1: fix quickpkg input in tb2file section (bug 616262) (diff) | |
download | portage-dac5089eb7908e9fd643f46c913515082077281e.tar.gz portage-dac5089eb7908e9fd643f46c913515082077281e.tar.bz2 portage-dac5089eb7908e9fd643f46c913515082077281e.zip |
Eventloop: fix deadlock involving idle_add/call_soon (bug 617550)
Guarantee that newly added idle_add/call_soon callbacks have an
opportunity to execute before the event loop decides to wait on
self._thread_condition without a timeout. This fixes a case where
the event loop would wait on self._thread_condition indefinitely,
even though a callback scheduled by the AsynchronousTask._async_wait
method needed to be executed first.
X-Gentoo-bug: 617550
X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=617550
Acked-by: Brian Dolbec <dolsen@gentoo.org>
-rw-r--r-- | pym/portage/util/_eventloop/EventLoop.py | 18 |
1 files changed, 16 insertions, 2 deletions
diff --git a/pym/portage/util/_eventloop/EventLoop.py b/pym/portage/util/_eventloop/EventLoop.py index 712838e3d..cd154005f 100644 --- a/pym/portage/util/_eventloop/EventLoop.py +++ b/pym/portage/util/_eventloop/EventLoop.py @@ -108,6 +108,15 @@ class EventLoop(object): self._poll_event_handler_ids = {} # Increment id for each new handler. self._event_handler_id = 0 + # New call_soon callbacks must have an opportunity to + # execute before it's safe to wait on self._thread_condition + # without a timeout, since delaying its execution indefinitely + # could lead to a deadlock. The following attribute stores the + # event handler id of the most recently added call_soon callback. + # If this attribute has changed since the last time that the + # call_soon callbacks have been called, then it's not safe to + # wait on self._thread_condition without a timeout. + self._call_soon_id = 0 # Use OrderedDict in order to emulate the FIFO queue behavior # of the AbstractEventLoop.call_soon method. self._idle_callbacks = OrderedDict() @@ -250,10 +259,15 @@ class EventLoop(object): if not event_handlers: with self._thread_condition: + prev_call_soon_id = self._call_soon_id if self._run_timeouts(): events_handled += 1 timeouts_checked = True - if not event_handlers and not events_handled and may_block: + + call_soon = prev_call_soon_id != self._call_soon_id + + if (not call_soon and not event_handlers + and not events_handled and may_block): # Block so that we don't waste cpu time by looping too # quickly. This makes EventLoop useful for code that needs # to wait for timeout callbacks regardless of whether or @@ -457,7 +471,7 @@ class EventLoop(object): @return: an integer ID """ with self._thread_condition: - source_id = self._new_source_id() + source_id = self._call_soon_id = self._new_source_id() self._idle_callbacks[source_id] = self._idle_callback_class( args=args, callback=callback, source_id=source_id) self._thread_condition.notify() |