From 878b808e9e2adc5545283e12cdd0cb106d8fd16a Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 26 Mar 2013 08:12:35 +0400 Subject: [PATCH] Workaround deadlock in ipython shutdown_hook is called after all non-daemon threads exit, but it is needed for them to exit. Thus I had to use daemon threads in ipython or find some hack to make .shutdown be called earlier. --- powerline/__init__.py | 12 ++++++++++-- powerline/ipython.py | 2 +- powerline/lib/threaded.py | 5 +++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/powerline/__init__.py b/powerline/__init__.py index 0bc3c4b1..49090a22 100644 --- a/powerline/__init__.py +++ b/powerline/__init__.py @@ -36,7 +36,7 @@ def load_json_config(config_file_path, load=json.load, open_file=open_file): class PowerlineState(object): - def __init__(self, logger, environ, getcwd, home): + def __init__(self, use_daemon_threads, logger, environ, getcwd, home): self.environ = environ self.getcwd = getcwd self.home = home or environ.get('HOME', None) @@ -103,6 +103,7 @@ class Powerline(object): renderer_module=None, run_once=False, logger=None, + use_daemon_threads = False, environ=os.environ, getcwd=getattr(os, 'getcwdu', os.getcwd), home=None): @@ -114,6 +115,7 @@ class Powerline(object): self.environ = environ self.getcwd = getcwd self.home = home + self.use_daemon_threads = use_daemon_threads self.config_paths = self.get_config_paths() @@ -174,7 +176,7 @@ class Powerline(object): self.logger.setLevel(level) self.logger.addHandler(handler) - self.pl = PowerlineState(logger=self.logger, environ=self.environ, getcwd=self.getcwd, home=self.home) + self.pl = PowerlineState(self.use_daemon_threads, self.logger, self.environ, self.getcwd, self.home) self.renderer_options = { 'term_truecolor': self.common_config.get('term_truecolor', False), @@ -234,6 +236,8 @@ class Powerline(object): **self.renderer_options) except Exception as e: self.pl.exception('Failed to construct renderer object: {0}', str(e)) + if not hasattr(self, 'renderer'): + raise else: self.renderer = renderer @@ -351,6 +355,8 @@ class Powerline(object): '''Lock renderer from modifications and run its ``.shutdown()`` method. ''' self.shutdown_event.set() + if self.use_daemon_threads and self.is_alive(): + self.thread.join() with self.renderer_lock: self.renderer.shutdown() @@ -359,6 +365,8 @@ class Powerline(object): def start(self): self.thread = Thread(target=self.run) + if self.use_daemon_threads: + self.thread.daemon = True self.thread.start() def run(self): diff --git a/powerline/ipython.py b/powerline/ipython.py index 64f53ca7..bed41514 100644 --- a/powerline/ipython.py +++ b/powerline/ipython.py @@ -6,7 +6,7 @@ from powerline.lib import mergedicts class IpythonPowerline(Powerline): def __init__(self): - super(IpythonPowerline, self).__init__('ipython') + super(IpythonPowerline, self).__init__('ipython', use_daemon_threads=True) def get_config_paths(self): if self.path: diff --git a/powerline/lib/threaded.py b/powerline/lib/threaded.py index 6ac4ab32..617ba060 100644 --- a/powerline/lib/threaded.py +++ b/powerline/lib/threaded.py @@ -11,6 +11,7 @@ class ThreadedSegment(object): min_sleep_time = 0.1 update_first = True interval = 1 + daemon = False def __init__(self): super(ThreadedSegment, self).__init__() @@ -49,6 +50,7 @@ class ThreadedSegment(object): def start(self): self.shutdown_event.clear() self.thread = Thread(target=self.run) + self.thread.daemon = self.daemon self.thread.start() def run(self): @@ -65,6 +67,8 @@ class ThreadedSegment(object): def shutdown(self): self.shutdown_event.set() + if self.daemon and self.is_alive(): + self.thread.join() def set_interval(self, interval=None): # Allowing “interval” keyword in configuration. @@ -81,6 +85,7 @@ class ThreadedSegment(object): def startup(self, pl, **kwargs): self.run_once = False self.pl = pl + self.daemon = pl.use_daemon_threads self.set_state(**kwargs)