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> |