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.
This commit is contained in:
ZyX 2013-03-26 08:12:35 +04:00
parent 27c9a05782
commit 878b808e9e
3 changed files with 16 additions and 3 deletions

View File

@ -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):

View File

@ -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:

View File

@ -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)