From 2b2580d9dac62aa720e5d996fa5102ee5caeffe7 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Tue, 25 Sep 2012 19:25:49 -0700 Subject: EventLoop: fix busy loop waiting for child pid This fixes a case where EventLoop could consume 100% CPU while waiting for a child process. It also fixes timeout calculations in python 2.x, where it was using integer division instead of float. --- pym/portage/util/_eventloop/EventLoop.py | 30 ++++++++++++++---------- pym/portage/util/_eventloop/PollSelectAdapter.py | 2 +- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/pym/portage/util/_eventloop/EventLoop.py b/pym/portage/util/_eventloop/EventLoop.py index 44a3c26b6..15d4ef214 100644 --- a/pym/portage/util/_eventloop/EventLoop.py +++ b/pym/portage/util/_eventloop/EventLoop.py @@ -137,15 +137,15 @@ class EventLoop(object): if not event_handlers: if self._run_timeouts(): events_handled += 1 - if not event_handlers: - if not events_handled and may_block and \ - self._timeout_interval is not None: + if not event_handlers and not events_handled and may_block: + timeout = self._get_poll_timeout() + if timeout is not None: # 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 # not any IO handlers are currently registered. try: - self._poll(timeout=self._timeout_interval) + self._poll(timeout=timeout) except StopIteration: pass if self._run_timeouts(): @@ -160,14 +160,7 @@ class EventLoop(object): if not event_queue: if may_block: - if self._child_handlers: - if self._timeout_interval is None: - timeout = self._sigchld_interval - else: - timeout = min(self._sigchld_interval, - self._timeout_interval) - else: - timeout = self._timeout_interval + timeout = self._get_poll_timeout() else: timeout = 0 @@ -194,6 +187,17 @@ class EventLoop(object): return bool(events_handled) + def _get_poll_timeout(self): + if self._child_handlers: + if self._timeout_interval is None: + timeout = self._sigchld_interval + else: + timeout = min(self._sigchld_interval, + self._timeout_interval) + else: + timeout = self._timeout_interval + return timeout + def child_watch_add(self, pid, callback, data=None): """ Like glib.child_watch_add(), sets callback to be called with the @@ -532,6 +536,6 @@ class _epoll_adapter(object): if timeout is None or timeout < 0: timeout = -1 elif timeout != 0: - timeout = timeout / 1000 + timeout = float(timeout) / 1000 return self._epoll_obj.poll(timeout) diff --git a/pym/portage/util/_eventloop/PollSelectAdapter.py b/pym/portage/util/_eventloop/PollSelectAdapter.py index 17e63d918..244788c57 100644 --- a/pym/portage/util/_eventloop/PollSelectAdapter.py +++ b/pym/portage/util/_eventloop/PollSelectAdapter.py @@ -64,7 +64,7 @@ class PollSelectAdapter(object): if timeout is not None and timeout < 0: timeout = None if timeout is not None: - select_args.append(timeout / 1000) + select_args.append(float(timeout) / 1000) select_events = select.select(*select_args) poll_events = [] -- cgit v1.2.3