wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

commit bdf6dacdc536957e0cbdfdb758fe1f884d3c5850
parent c7994d542e17cf67618cebfe205dc08165f4a739
Author: Kris Maglione <kris@suckless.org>
Date:   Thu,  1 Jul 2010 21:45:27 -0400

[python] Fix some deadlock issues.

Diffstat:
alternative_wmiircs/python/pygmi/event.py | 11++++++-----
alternative_wmiircs/python/pygmi/fs.py | 48+++++++++++++++++++++++++++---------------------
alternative_wmiircs/python/pygmi/monitor.py | 11++++++-----
alternative_wmiircs/python/pyxp/mux.py | 86++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
4 files changed, 96 insertions(+), 60 deletions(-)

diff --git a/alternative_wmiircs/python/pygmi/event.py b/alternative_wmiircs/python/pygmi/event.py @@ -164,7 +164,7 @@ class Keys(object): """ self.modes = {} self.modelist = [] - self._set_mode('main', False) + self.mode = 'main' self.defs = {} events.bind(Key=self.dispatch) @@ -179,17 +179,18 @@ class Keys(object): } self.modelist.append(mode) - def _set_mode(self, mode, execute=True): + mode = property(lambda self: self._mode, + doc="The current mode for which to dispatch keys") + @mode.setter + def mode(self, mode): self._add_mode(mode) self._mode = mode self._keys = dict((k % self.defs, v) for k, v in self.modes[mode]['keys'].items() + self.modes[mode]['import'].items()); - if execute: + if hasattr(self, 'defs'): client.write('/keys', '\n'.join(self._keys.keys()) + '\n') - mode = property(lambda self: self._mode, _set_mode, - doc="The current mode for which to dispatch keys") @prop(doc="Returns a short help text describing the bound keys in all modes") def help(self): diff --git a/alternative_wmiircs/python/pygmi/fs.py b/alternative_wmiircs/python/pygmi/fs.py @@ -11,6 +11,7 @@ __all__ = ('wmii', 'Tags', 'Tag', 'Area', 'Frame', 'Client', 'Button', 'Colors', 'Color', 'Toggle', 'Always', 'Never') spacere = re.compile(r'\s') +sentinel = {} class utf8(object): def __str__(self): @@ -67,7 +68,6 @@ class Ctl(object): tuples, each containing a decoder and encoder function for the property's plain text value. """ - sentinel = {} ctl_types = {} ctl_hasid = False ctl_open = 'aopen' @@ -312,14 +312,14 @@ class liveprop(object): self.get = get self.attr = str(self) def __get__(self, area, cls): - if getattr(area, self.attr, None) is not None: + if getattr(area, self.attr, sentinel) is not sentinel: return getattr(area, self.attr) return self.get(area) def __set__(self, area, val): setattr(area, self.attr, val) class Area(object): - def __init__(self, tag, ord, screen='sel', offset=None, width=None, height=None, frames=None): + def __init__(self, tag, ord, screen='sel', offset=sentinel, width=sentinel, height=sentinel, frames=sentinel): self.tag = tag if ':' in str(ord): screen, ord = ord.split(':', 2) @@ -344,17 +344,20 @@ class Area(object): @property def spec(self): - return '%s:%s' % (self.screen, self.ord) + if self.screen is not None: + return '%s:%s' % (self.screen, self.ord) + return self.ord - def _get_mode(self): + @property + def mode(self): for k, v in self.tag.iteritems(): if k == 'colmode': v = v.split(' ') if v[0] == self.ord: return v[1] - mode = property( - _get_mode, - lambda self, val: self.tag.set('colmode %s' % self.spec, val)) + @mode.setter + def mode(self, val): + self.tag['colmode %s' % self.spec] = val def grow(self, dir, amount=None): self.tag.grow(self, dir, amount) @@ -364,7 +367,7 @@ class Area(object): class Frame(object): live = False - def __init__(self, client, area=None, ord=None, offset=None, height=None): + def __init__(self, client, area=sentinel, ord=sentinel, offset=sentinel, height=sentinel): self.client = client self.ord = ord self.offset = offset @@ -414,21 +417,24 @@ class Tag(Dir): dir = ' '.join(dir) return dir - def _set_selected(self, frame): + @property + def selected(self): + return tuple(self['select'].split(' ')) + @selected.setter + def selected(self, frame): if not isinstance(frame, basestring) or ' ' not in frame: frame = self.framespec(frame) self['select'] = frame - selected = property(lambda self: tuple(self['select'].split(' ')), - _set_selected) - def _get_selclient(self): + @property + def selclient(self): for k, v in self.iteritems(): if k == 'select' and 'client' in v: return Client(v.split(' ')[1]) return None - selclient = property(_get_selclient, - lambda self, val: self.set('select', - self.framespec(val))) + @selclient.setter + def selclient(self, val): + self['select'] = self.framespec(val) @property def selcol(self): @@ -437,9 +443,9 @@ class Tag(Dir): @property def index(self): areas = [] - for l in [l.split(' ') + for l in (l.split(' ') for l in client.readlines('%s/index' % self.path) - if l]: + if l): if l[0] == '#': m = re.match(r'(?:(\d+):)?(\d+|~)', l[1]) if m.group(2) == '~': @@ -447,7 +453,7 @@ class Tag(Dir): height=l[3], frames=[]) else: area = Area(tag=self, screen=m.group(1) or 0, - ord=m.group(2), offset=l[2], width=l[3], + height=None, ord=m.group(2), offset=l[2], width=l[3], frames=[]) areas.append(area) i = 0 @@ -797,12 +803,12 @@ class Tags(object): self.tags[tag].button.label = urgent and '*' + tag or tag def next(self, reverse=False): - tags = [t for t in wmii.tags if t.id not in self.ignore] + tags = [t for t in wmii.tags if t not in self.ignore] tags.append(tags[0]) if reverse: tags.reverse() for i in range(0, len(tags)): - if tags[i] == self.sel: + if tags[i] == self.sel.id: return tags[i+1] return self.sel diff --git a/alternative_wmiircs/python/pygmi/monitor.py b/alternative_wmiircs/python/pygmi/monitor.py @@ -107,7 +107,12 @@ class Monitor(object): return None _active = True - def _set_active(self, val): + @property + def active(self): + return self._active + + @active.setter + def active(self, val): with self.lock: self._active = bool(val) if val: @@ -115,8 +120,4 @@ class Monitor(object): else: self.button.remove() - active = property( - lambda self: self._active, - _set_active) - # vim:se sts=4 sw=4 et: diff --git a/alternative_wmiircs/python/pyxp/mux.py b/alternative_wmiircs/python/pyxp/mux.py @@ -39,6 +39,9 @@ class Mux(object): self.maxtag = maxtag self.muxer = None + self.async_mux = Queue(self.mux) + self.async_dispatch = Queue(self.async_dispatch) + if isinstance(con, basestring): con = dial(con) self.fd = con @@ -48,8 +51,8 @@ class Mux(object): def mux(self, rpc): try: - rpc.waiting = True self.lock.acquire() + rpc.waiting = True while self.muxer and self.muxer != rpc and rpc.data is None: rpc.wait() @@ -69,7 +72,7 @@ class Mux(object): self.lock.acquire() self.electmuxer() except Exception, e: - traceback.print_exc(sys.stdout) + traceback.print_exc(sys.stderr) if self.flush: self.flush(self, rpc.data) raise e @@ -77,36 +80,26 @@ class Mux(object): if self.lock._is_owned(): self.lock.release() - if rpc.async: - if callable(rpc.async): - rpc.async(self, rpc.data) - else: - return rpc.data + return rpc.data def rpc(self, dat, async=None): rpc = self.newrpc(dat, async) if async: - with self.lock: - if self.muxer is None: - self.electmuxer() + self.async_mux.push(rpc) else: return self.mux(rpc) + def async_dispatch(self, rpc): + self.async_mux.pop(rpc) + rpc.async(self, rpc.data) + def electmuxer(self): - async = None for rpc in self.queue: - if self.muxer != rpc: - if rpc.async: - async = rpc - else: - self.muxer = rpc - rpc.notify() - return + if self.muxer != rpc and rpc.waiting: + self.muxer = rpc + rpc.notify() + return self.muxer = None - if async: - self.muxer = async - t = Thread(target=self.mux, args=(async,)) - t.start() def dispatch(self, dat): tag = dat.tag @@ -156,8 +149,7 @@ class Mux(object): data += self.fd.recv(len - 4) return self.process(data) except Exception, e: - traceback.print_exc(sys.stdout) - print repr(data) + traceback.print_exc(sys.stderr) return None def newrpc(self, dat, async=None): @@ -181,14 +173,50 @@ class Rpc(Condition): self.mux = mux self.orig = data self.data = None - self.waiting = False self.async = async + self.waiting = False def dispatch(self, data=None): self.data = data - if not self.async or self.waiting: - self.notify() - elif callable(self.async): - Thread(target=self.async, args=(self.mux, data)).start() + self.notify() + if callable(self.async): + self.mux.async_dispatch(self) + +class Queue(Thread): + def __init__(self, op): + super(Queue, self).__init__() + self.cond = Condition() + self.op = op + self.queue = [] + self.daemon = True + + def __call__(self, item): + return self.push(item) + + def push(self, item): + with self.cond: + self.queue.append(item) + if not self.is_alive(): + self.start() + self.cond.notify() + def pop(self, item): + with self.cond: + if item in self.queue: + self.queue.remove(item) + return True + return False + + def run(self): + self.cond.acquire() + while True: + while self.queue: + item = self.queue.pop(0) + self.cond.release() + try: + self.op(item) + except Exception, e: + traceback.print_exc(sys.stderr) + self.cond.acquire() + self.cond.wait() # vim:se sts=4 sw=4 et: