aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2017-05-05 02:07:38 -0700
committerZac Medico <zmedico@gentoo.org>2017-05-05 11:32:45 -0700
commitdac5089eb7908e9fd643f46c913515082077281e (patch)
tree229627945cc3033eb2c7f596754b0a1aa8a98c4a
parentman/emerge.1: fix quickpkg input in tb2file section (bug 616262) (diff)
downloadportage-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.py18
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()