On Fri, 5 May 2017 02:12:53 -0700 Zac Medico <zmed...@gentoo.org> wrote:
> 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 > --- > pym/portage/util/_eventloop/EventLoop.py | 18 ++++++++++++++++-- > 1 file changed, 16 insertions(+), 2 deletions(-) > > diff --git a/pym/portage/util/_eventloop/EventLoop.py > b/pym/portage/util/_eventloop/EventLoop.py index 712838e..b7c8762 > 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 = > bool(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() looks good -- Brian Dolbec <dolsen>