EventLoop: fix busy loop waiting for child pid
authorZac Medico <zmedico@gentoo.org>
Wed, 26 Sep 2012 02:25:49 +0000 (19:25 -0700)
committerZac Medico <zmedico@gentoo.org>
Wed, 26 Sep 2012 02:25:49 +0000 (19:25 -0700)
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
pym/portage/util/_eventloop/PollSelectAdapter.py

index 44a3c26b688debdb5b2b51581ca3e216fd96405a..15d4ef214ee4eae6a7eb7ba1ed135b219d334eda 100644 (file)
@@ -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)
index 17e63d918a4aa42b7d04d580cf4e664681d49116..244788c57e17bdab36a6f9804a2e3370e8c3f10e 100644 (file)
@@ -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 = []