Fix high cpu usage with asyncioeventloop

Apparently asyncioeventloop needs more than a shim to work properly
in urwid <= 1.2.1. Remove the shim and revisit once urwid 1.3.0 is
packaged in Debian/Ubuntu

Fixes #11

Signed-off-by: Adam Stokes <adam.stokes@ubuntu.com>
This commit is contained in:
Adam Stokes 2015-07-01 17:05:27 -04:00
parent b649c5b0fb
commit a986e80595
3 changed files with 6 additions and 153 deletions

View File

@ -14,13 +14,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
import asyncio
import urwid
import urwid.curses_display
if urwid.version.VERSION >= (1, 3, 0):
from urwid import AsyncioEventLoop
else:
from subiquity.loop_shim import AsyncioEventLoop
from subiquity.routes import Routes
from subiquity.palette import STYLES, STYLES_MONO
@ -51,17 +46,15 @@ class BaseController:
try:
self.loop.draw_screen()
except AssertionError as e:
log.critical(e)
log.critical("Redraw screen error: {}".format(e))
def set_alarm_in(self, interval, cb):
self.loop.set_alarm_in(interval, cb)
return
def update(self, *args, **kwds):
route = Routes.current_idx()
if route == 0:
self.begin()
self.set_alarm_in(1, self.update)
""" Update loop """
pass
def exit(self):
raise urwid.ExitMainLoop()
@ -96,23 +89,18 @@ class BaseController:
else:
additional_opts['screen'].set_terminal_properties(colors=256)
additional_opts['screen'].reset_default_terminal_palette()
additional_opts['event_loop'] = AsyncioEventLoop(
loop=asyncio.get_event_loop())
self.loop = urwid.MainLoop(
self.ui, palette, **additional_opts)
try:
if self.opts.run_on_serial:
self.loop.screen.start()
self.begin()
self.set_alarm_in(0.05, self.begin)
self.loop.run()
except:
log.exception("Exception in controller.run():")
raise
def begin(self):
def begin(self, *args, **kwargs):
""" Initializes the first controller for installation """
Routes.reset()
initial_controller = Routes.first()

View File

@ -1,131 +0,0 @@
# Copyright 2015 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
from urwid.main_loop import ExitMainLoop
log = logging.getLogger('subiquity.loop_shim')
class AsyncioEventLoop(object):
"""
Event loop based on the standard library ``asyncio`` module.
``asyncio`` is new in Python 3.4, but also exists as a backport on PyPI for
Python 3.3. The ``trollius`` package is available for older Pythons with
slightly different syntax, but also works with this loop.
"""
_we_started_event_loop = False
_idle_emulation_delay = 1.0 / 256 # a short time (in seconds)
def __init__(self, **kwargs):
log.debug("Running the AsyncioEventLoop shim because current "
"version of urwid < 1.3.0")
if 'loop' in kwargs:
self._loop = kwargs.pop('loop')
else:
import asyncio
self._loop = asyncio.get_event_loop()
def alarm(self, seconds, callback):
"""
Call callback() a given time from now. No parameters are
passed to callback.
Returns a handle that may be passed to remove_alarm()
seconds -- time in seconds to wait before calling callback
callback -- function to call from event loop
"""
return self._loop.call_later(seconds, callback)
def remove_alarm(self, handle):
"""
Remove an alarm.
Returns True if the alarm exists, False otherwise
"""
existed = not handle._cancelled
handle.cancel()
return existed
def watch_file(self, fd, callback):
"""
Call callback() when fd has some data to read. No parameters
are passed to callback.
Returns a handle that may be passed to remove_watch_file()
fd -- file descriptor to watch for input
callback -- function to call when input is available
"""
self._loop.add_reader(fd, callback)
return fd
def remove_watch_file(self, handle):
"""
Remove an input file.
Returns True if the input file exists, False otherwise
"""
return self._loop.remove_reader(handle)
def enter_idle(self, callback):
"""
Add a callback for entering idle.
Returns a handle that may be passed to remove_idle()
"""
# XXX there's no such thing as "idle" in most event loops; this fakes
# it the same way as Twisted, by scheduling the callback to be called
# repeatedly
mutable_handle = [None]
def faux_idle_callback():
callback()
mutable_handle[0] = self._loop.call_later(
self._idle_emulation_delay, faux_idle_callback)
mutable_handle[0] = self._loop.call_later(
self._idle_emulation_delay, faux_idle_callback)
return mutable_handle
def remove_enter_idle(self, handle):
"""
Remove an idle callback.
Returns True if the handle was removed.
"""
# `handle` is just a list containing the current actual handle
return self.remove_alarm(handle[0])
_exc_info = None
def _exception_handler(self, loop, context):
exc = context.get('exception')
if exc:
loop.stop()
if not isinstance(exc, ExitMainLoop):
# Store the exc_info so we can re-raise after the loop stops
import sys
self._exc_info = sys.exc_info()
else:
loop.default_exception_handler(context)
def run(self):
"""
Start the event loop. Exit the loop when any callback raises
an exception. If ExitMainLoop is raised, exit cleanly.
"""
self._loop.set_exception_handler(self._exception_handler)
self._loop.run_forever()
if self._exc_info:
raise Exception(self._exc_info[0],
self._exc_info[1],
self._exc_info[2])
self._exc_info = None

View File

@ -27,7 +27,7 @@ class Header(WidgetWrap):
:returns: Header()
"""
def __init__(self, title="Ubuntu Server Installer", excerpt=""):
def __init__(self, title="", excerpt=""):
title_widget = Padding.center_79(Color.body(Text(title)))
excerpt_widget = Padding.center_79(Color.body(Text(excerpt)))
pile = Pile([Text(""),
@ -58,10 +58,6 @@ class Body(WidgetWrap):
def __init__(self):
text = [
Padding.line_break(""),
Padding.center_79(
Text("Welcome to the Ubuntu Server Installation",
align="center")),
Padding.line_break("")
]
w = (SimpleList(text))
super().__init__(w)