Also using asyncio for the display thread.

When I tried this before threading was working better.
Now asyncio is doing better.

Recently, exceptions were happening occasionaly in the update
thread. I guess due to races. They should go away now.

From now on, if a coroutine takes too long the interface will hitch.
Should investigate if sync_to_filesystem is taking too long and
if it can yield.

There are no uses of threading now.
This commit is contained in:
Andrew Hamilton 2016-10-30 12:42:50 +01:00
parent c99dd27dc6
commit 62fa8269dc
2 changed files with 19 additions and 36 deletions

View file

@ -4,13 +4,13 @@
# Copyright (C) 2015-2016 Andrew Hamilton. All rights reserved. # Copyright (C) 2015-2016 Andrew Hamilton. All rights reserved.
# Licensed under the Artistic License 2.0. # Licensed under the Artistic License 2.0.
import asyncio
import collections import collections
import contextlib import contextlib
import itertools import itertools
import os import os
import signal import signal
import sys import sys
import threading
import urwid import urwid
import urwid.raw_display import urwid.raw_display
@ -401,6 +401,9 @@ class Placeholder:
return self.widget.appearance(dimensions) return self.widget.appearance(dimensions)
##########################
def draw_screen(widget): def draw_screen(widget):
appearance = widget.appearance(os.get_terminal_size()) appearance = widget.appearance(os.get_terminal_size())
print(terminal.move(0, 0), *appearance, sep="", end="", flush=True) print(terminal.move(0, 0), *appearance, sep="", end="", flush=True)
@ -433,43 +436,27 @@ def _urwid_screen():
screen.stop() screen.stop()
_UPDATE_THREAD_STOPPED = threading.Event() async def _update_screen(screen_widget, appearance_changed_event):
def _update_screen(main_widget, appearance_changed_event):
while True: while True:
appearance_changed_event.wait() await appearance_changed_event.wait()
appearance_changed_event.clear() appearance_changed_event.clear()
if _UPDATE_THREAD_STOPPED.is_set(): patch_screen(screen_widget)
break
patch_screen(main_widget)
def main(loop, appearance_changed_event, screen, exit_loop=None): def main(loop, appearance_changed_event, screen_widget, exit_loop=None):
appearance_changed_event.set() appearance_changed_event.set()
update_display_thread = threading.Thread(
target=_update_screen, args=(screen, appearance_changed_event),
daemon=True)
def exit_loop_():
loop.stop()
if exit_loop is None: if exit_loop is None:
exit_loop = exit_loop_ exit_loop = loop.stop
loop.add_signal_handler(signal.SIGWINCH, appearance_changed_event.set) loop.add_signal_handler(signal.SIGWINCH, appearance_changed_event.set)
loop.add_signal_handler(signal.SIGINT, exit_loop) loop.add_signal_handler(signal.SIGINT, exit_loop)
loop.add_signal_handler(signal.SIGTERM, exit_loop) loop.add_signal_handler(signal.SIGTERM, exit_loop)
asyncio.ensure_future(_update_screen(screen_widget,
appearance_changed_event))
with terminal.hidden_cursor(): with terminal.hidden_cursor():
with _urwid_screen() as urwid_screen: with _urwid_screen() as urwid_screen:
def on_input(urwid_screen): def on_input(urwid_screen):
for event in urwid_screen.get_input(): for event in urwid_screen.get_input():
screen.on_input_event(event) screen_widget.on_input_event(event)
loop.add_reader(sys.stdin, on_input, urwid_screen) loop.add_reader(sys.stdin, on_input, urwid_screen)
update_display_thread.start() loop.run_forever()
try:
loop.run_forever()
finally:
_UPDATE_THREAD_STOPPED.set()
appearance_changed_event.set()
update_display_thread.join()
# loop.close()

16
vigil
View file

@ -33,7 +33,6 @@ import signal
import subprocess import subprocess
import sys import sys
import tempfile import tempfile
import threading
import time import time
import docopt import docopt
@ -198,7 +197,6 @@ class Summary:
self._view_widget = fill3.View.from_widget(self) self._view_widget = fill3.View.from_widget(self)
self.__cursor_position = (0, 0) self.__cursor_position = (0, 0)
self.closest_placeholder_generator = None self.closest_placeholder_generator = None
self._lock = threading.Lock()
self._cache = {} self._cache = {}
self.is_directory_sort = True self.is_directory_sort = True
self._max_width = None self._max_width = None
@ -296,12 +294,11 @@ class Summary:
yield result yield result
def get_closest_placeholder(self): def get_closest_placeholder(self):
with self._lock: try:
try: return self.closest_placeholder_generator.send(None)
return self.closest_placeholder_generator.send(None) except AttributeError:
except AttributeError: self.closest_placeholder_generator = self._placeholder_spiral()
self.closest_placeholder_generator = self._placeholder_spiral() return self.closest_placeholder_generator.send(None)
return self.closest_placeholder_generator.send(None)
def appearance_dimensions(self): def appearance_dimensions(self):
return self._max_path_length + 1 + self._max_width, len(self._column) return self._max_path_length + 1 + self._max_width, len(self._column)
@ -919,7 +916,6 @@ def load_state(pickle_path, jobs_added_event, appearance_changed_event,
screen._appearance_changed_event = appearance_changed_event screen._appearance_changed_event = appearance_changed_event
screen._main_loop = loop screen._main_loop = loop
summary = screen._summary summary = screen._summary
summary._lock = threading.Lock()
summary._jobs_added_event = jobs_added_event summary._jobs_added_event = jobs_added_event
summary._root_path = root_path summary._root_path = root_path
log = screen._log log = screen._log
@ -943,7 +939,7 @@ def main(root_path, loop, worker_count=None, is_sandboxed=True,
worker_count = multiprocessing.cpu_count() * 2 worker_count = multiprocessing.cpu_count() * 2
pickle_path = os.path.join(tools.CACHE_PATH, "summary.pickle") pickle_path = os.path.join(tools.CACHE_PATH, "summary.pickle")
jobs_added_event = asyncio.Event() jobs_added_event = asyncio.Event()
appearance_changed_event = threading.Event() appearance_changed_event = asyncio.Event()
summary, screen, log, is_first_run = load_state( summary, screen, log, is_first_run = load_state(
pickle_path, jobs_added_event, appearance_changed_event, root_path, pickle_path, jobs_added_event, appearance_changed_event, root_path,
loop) loop)