Gentoo Archives: gentoo-portage-dev

From: Brian Dolbec <dolsen@g.o>
To: gentoo-portage-dev@l.g.o
Subject: Re: [gentoo-portage-dev] [PATCH] Eventloop: fix deadlock involving idle_add/call_soon (bug 617550)
Date: Fri, 05 May 2017 17:51:15
Message-Id: 20170505105102.03b0468b.dolsen@gentoo.org
In Reply to: [gentoo-portage-dev] [PATCH] Eventloop: fix deadlock involving idle_add/call_soon (bug 617550) by Zac Medico
1 On Fri, 5 May 2017 02:12:53 -0700
2 Zac Medico <zmedico@g.o> wrote:
3
4 > Guarantee that newly added idle_add/call_soon callbacks have an
5 > opportunity to execute before the event loop decides to wait on
6 > self._thread_condition without a timeout. This fixes a case where
7 > the event loop would wait on self._thread_condition indefinitely,
8 > even though a callback scheduled by the AsynchronousTask._async_wait
9 > method needed to be executed first.
10 >
11 > X-Gentoo-bug: 617550
12 > X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=617550
13 > ---
14 > pym/portage/util/_eventloop/EventLoop.py | 18 ++++++++++++++++--
15 > 1 file changed, 16 insertions(+), 2 deletions(-)
16 >
17 > diff --git a/pym/portage/util/_eventloop/EventLoop.py
18 > b/pym/portage/util/_eventloop/EventLoop.py index 712838e..b7c8762
19 > 100644 --- a/pym/portage/util/_eventloop/EventLoop.py
20 > +++ b/pym/portage/util/_eventloop/EventLoop.py
21 > @@ -108,6 +108,15 @@ class EventLoop(object):
22 > self._poll_event_handler_ids = {}
23 > # Increment id for each new handler.
24 > self._event_handler_id = 0
25 > + # New call_soon callbacks must have an opportunity to
26 > + # execute before it's safe to wait on
27 > self._thread_condition
28 > + # without a timeout, since delaying its execution
29 > indefinitely
30 > + # could lead to a deadlock. The following attribute
31 > stores the
32 > + # event handler id of the most recently added
33 > call_soon callback.
34 > + # If this attribute has changed since the last time
35 > that the
36 > + # call_soon callbacks have been called, then it's
37 > not safe to
38 > + # wait on self._thread_condition without a timeout.
39 > + self._call_soon_id = 0
40 > # Use OrderedDict in order to emulate the FIFO queue
41 > behavior # of the AbstractEventLoop.call_soon method.
42 > self._idle_callbacks = OrderedDict()
43 > @@ -250,10 +259,15 @@ class EventLoop(object):
44 >
45 > if not event_handlers:
46 > with self._thread_condition:
47 > + prev_call_soon_id =
48 > self._call_soon_id if self._run_timeouts():
49 > events_handled += 1
50 > timeouts_checked = True
51 > - if not event_handlers and not
52 > events_handled and may_block: +
53 > + call_soon =
54 > bool(prev_call_soon_id != self._call_soon_id) +
55 > + if (not call_soon and not
56 > event_handlers
57 > + and not events_handled and
58 > may_block): # Block so that we don't waste cpu time by looping too
59 > # quickly. This makes
60 > EventLoop useful for code that needs # to wait for timeout callbacks
61 > regardless of whether or @@ -457,7 +471,7 @@ class EventLoop(object):
62 > @return: an integer ID
63 > """
64 > with self._thread_condition:
65 > - source_id = self._new_source_id()
66 > + source_id = self._call_soon_id =
67 > self._new_source_id() self._idle_callbacks[source_id] =
68 > self._idle_callback_class( args=args, callback=callback,
69 > source_id=source_id) self._thread_condition.notify()
70
71
72 looks good
73 --
74 Brian Dolbec <dolsen>

Replies