[python] Fix some deadlock issues.

This commit is contained in:
Kris Maglione 2010-07-01 21:45:27 -04:00
parent c7994d542e
commit bdf6dacdc5
4 changed files with 96 additions and 60 deletions

View File

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

View File

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

View File

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

View File

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