Remove ThreadedSegment.write_lock

Assuming getattr(self, 'update_value') and setattr(self, 'update_value', value) 
are atomic. True with cpython unless somebody defined __getattribute__ or 
__setattr__.
This commit is contained in:
ZyX 2013-03-30 14:07:24 +04:00
parent ff6fd64339
commit 29f29213a9
5 changed files with 54 additions and 57 deletions

View File

@ -84,7 +84,7 @@ endfunction
augroup Powerline
autocmd! ColorScheme * :exec s:powerline_pycmd 'powerline.renderer.reset_highlight()'
autocmd! VimEnter * :redrawstatus!
autocmd! VimLeave * :exec s:powerline_pycmd 'powerline.shutdown()'
autocmd! VimLeavePre * :exec s:powerline_pycmd 'powerline.shutdown()'
augroup END
exec s:powerline_pycmd 'powerline = VimPowerline()'

View File

@ -16,33 +16,39 @@ class ThreadedSegment(object):
def __init__(self):
super(ThreadedSegment, self).__init__()
self.shutdown_event = Event()
self.write_lock = Lock()
self.run_once = True
self.thread = None
self.skip = False
self.crashed_value = None
self.update_value = None
def __call__(self, pl, update_first=True, **kwargs):
if self.run_once:
self.pl = pl
self.set_state(**kwargs)
self.update()
update_value = self.get_update_value(True)
elif not self.is_alive():
# Without this we will not have to wait long until receiving bug “I
# opened vim, but branch information is only shown after I move
# cursor”.
#
# If running once .update() is called in __call__.
if update_first and self.update_first:
self.update()
update_value = self.get_update_value(update_first and self.update_first)
self.start()
elif not self.updated:
self.update()
update_value = self.get_update_value(True)
else:
update_value = self.update_value
if self.skip:
return self.crashed_value
with self.write_lock:
return self.render(update_first=update_first, pl=pl, **kwargs)
return self.render(update_value, update_first=update_first, pl=pl, **kwargs)
def get_update_value(self, update=False):
if update:
self.update_value = self.update(self.update_value)
return self.update_value
def is_alive(self):
return self.thread and self.thread.is_alive()
@ -57,7 +63,7 @@ class ThreadedSegment(object):
while not self.shutdown_event.is_set():
start_time = monotonic()
try:
self.update()
self.update(self.update_value)
except Exception as e:
self.error('Exception while updating: {0}', str(e))
self.skip = True
@ -115,48 +121,42 @@ class KwThreadedSegment(ThreadedSegment):
def __init__(self):
super(KwThreadedSegment, self).__init__()
self.queries = {}
self.crashed = set()
self.updated = True
self.update_value = ({}, set())
@staticmethod
def key(**kwargs):
return frozenset(kwargs.items())
def render(self, update_first, **kwargs):
def render(self, update_value, update_first, **kwargs):
queries, crashed = update_value
key = self.key(**kwargs)
if key in self.crashed:
if key in crashed:
return self.crashed_value
try:
update_state = self.queries[key][1]
update_state = queries[key][1]
except KeyError:
# Allow only to forbid to compute missing values: in either user
# configuration or in subclasses.
update_state = self.compute_state(key) if update_first and self.update_first or self.run_once else None
# No locks: render method is already running with write_lock acquired.
self.queries[key] = (monotonic(), update_state)
queries[key] = (monotonic(), update_state)
return self.render_one(update_state, **kwargs)
def update(self):
def update(self, old_update_value):
updates = {}
removes = []
for key, (last_query_time, state) in list(self.queries.items()):
crashed = set()
update_value = (updates, crashed)
queries = old_update_value[0]
for key, (last_query_time, state) in queries.items():
if last_query_time < monotonic() < last_query_time + self.drop_interval:
try:
updates[key] = (last_query_time, self.compute_state(key))
except Exception as e:
self.exception('Exception while computing state for {0}: {1}', repr(key), str(e))
with self.write_lock:
self.crashed.add(key)
else:
removes.append(key)
with self.write_lock:
self.queries.update(updates)
self.crashed -= set(updates)
for key in removes:
self.queries.pop(key)
crashed.add(key)
return update_value
def set_state(self, interval=None, update_first=True, **kwargs):
self.set_interval(interval)
@ -164,9 +164,6 @@ class KwThreadedSegment(ThreadedSegment):
if self.update_first:
self.update_first = update_first
with self.write_lock:
self.queries.clear()
@staticmethod
def render_one(update_state, **kwargs):
return update_state

View File

@ -39,13 +39,13 @@ class RepositorySegment(KwThreadedSegment):
def key(pl, **kwargs):
return os.path.abspath(pl.getcwd())
def update(self):
def update(self, *args):
# .compute_state() is running only in this method, and only in one
# thread, thus operations with .directories do not need write locks
# (.render() method is not using .directories). If this is changed
# .directories needs redesigning
self.directories.clear()
super(RepositorySegment, self).update()
return super(RepositorySegment, self).update(*args)
def compute_state(self, path):
repo = guess(path=path)
@ -231,19 +231,19 @@ def _external_ip(query_url='http://ipv4.icanhazip.com/'):
class ExternalIpSegment(ThreadedSegment):
interval = 10
def set_state(self, query_url='http://ipv4.icanhazip.com/', **kwargs):
self.query_url = query_url
super(ExternalIpSegment, self).set_state(**kwargs)
def update(self):
ip = _external_ip(query_url=self.query_url)
with self.write_lock:
self.ip = ip
def update(self, old_ip):
return _external_ip(query_url=self.query_url)
def render(self, **kwargs):
if not hasattr(self, 'ip'):
def render(self, ip, **kwargs):
if not ip:
return None
return [{'contents': self.ip, 'divider_highlight_group': 'background:divider'}]
return [{'contents': ip, 'divider_highlight_group': 'background:divider'}]
external_ip = with_docstring(ExternalIpSegment(),
@ -357,10 +357,9 @@ class WeatherSegment(ThreadedSegment):
def set_state(self, location_query=None, **kwargs):
self.location = location_query
self.url = None
self.condition = {}
super(WeatherSegment, self).set_state(**kwargs)
def update(self):
def update(self, old_weather):
import json
if not self.url:
@ -398,31 +397,31 @@ class WeatherSegment(ThreadedSegment):
icon_names = ('unknown',)
self.error('Unknown condition code: {0}', condition_code)
with self.write_lock:
self.temp = temp
self.icon_names = icon_names
return (temp, icon_names)
def render(self, icons=None, unit='C', temp_format=None, temp_coldest=-30, temp_hottest=40, **kwargs):
if not hasattr(self, 'icon_names'):
def render(self, weather, icons=None, unit='C', temp_format=None, temp_coldest=-30, temp_hottest=40, **kwargs):
if not weather:
return None
for icon_name in self.icon_names:
temp, icon_names = weather
for icon_name in icon_names:
if icons:
if icon_name in icons:
icon = icons[icon_name]
break
else:
icon = weather_conditions_icons[self.icon_names[-1]]
icon = weather_conditions_icons[icon_names[-1]]
temp_format = temp_format or ('{temp:.0f}' + temp_units[unit])
temp = temp_conversions[unit](self.temp)
if self.temp <= temp_coldest:
converted_temp = temp_conversions[unit](temp)
if temp <= temp_coldest:
gradient_level = 0
elif self.temp >= temp_hottest:
elif temp >= temp_hottest:
gradient_level = 100
else:
gradient_level = (self.temp - temp_coldest) * 100.0 / (temp_hottest - temp_coldest)
groups = ['weather_condition_' + icon_name for icon_name in self.icon_names] + ['weather_conditions', 'weather']
gradient_level = (temp - temp_coldest) * 100.0 / (temp_hottest - temp_coldest)
groups = ['weather_condition_' + icon_name for icon_name in icon_names] + ['weather_conditions', 'weather']
return [
{
'contents': icon + ' ',
@ -430,7 +429,7 @@ class WeatherSegment(ThreadedSegment):
'divider_highlight_group': 'background:divider',
},
{
'contents': temp_format.format(temp=temp),
'contents': temp_format.format(temp=converted_temp),
'highlight_group': ['weather_temp_gradient', 'weather_temp', 'weather'],
'draw_divider': False,
'divider_highlight_group': 'background:divider',

View File

@ -318,13 +318,13 @@ class RepositorySegment(KwWindowThreadedSegment):
# FIXME os.getcwd() is not a proper variant for non-current buffers
return segment_info['buffer'].name or os.getcwd()
def update(self):
def update(self, *args):
# .compute_state() is running only in this method, and only in one
# thread, thus operations with .directories do not need write locks
# (.render() method is not using .directories). If this is changed
# .directories needs redesigning
self.directories.clear()
super(RepositorySegment, self).update()
return super(RepositorySegment, self).update(*args)
def compute_state(self, path):
repo = guess(path=path)

View File

@ -12,6 +12,7 @@ class Pl(object):
self.prefix = None
self.environ = {}
self.home = None
self.use_daemon_threads = True
def getcwd(self):
if isinstance(self._cwd, Exception):