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:
parent
b649c5b0fb
commit
a986e80595
|
@ -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()
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue