Replace dodgy synchronization

Use Queue.Queue() rather than event.
pull/35/head
David Wilson 8 years ago
parent e62b891b9a
commit 07ba2de7b0

@ -4,7 +4,7 @@
Python External Execution Contexts.
'''
import atexit
import Queue
import cPickle
import cStringIO
import commands
@ -124,9 +124,7 @@ class Channel(object):
def __init__(self, stream, handle):
self._stream = stream
self._handle = handle
self._wake_event = threading.Event()
self._queue_lock = threading.Lock()
self._queue = []
self._queue = Queue.Queue()
self._stream.AddHandleCB(self._InternalReceive, handle)
def _InternalReceive(self, killed, data):
@ -146,12 +144,7 @@ class Channel(object):
)
'''
LOG.debug('%r._InternalReceive(%r, %r)', self, killed, data)
self._queue_lock.acquire()
try:
self._queue.append((killed or data[0], killed or data[1]))
self._wake_event.set()
finally:
self._queue_lock.release()
self._queue.put((killed or data[0], killed or data[1]))
def Close(self):
'''
@ -179,22 +172,15 @@ class Channel(object):
object
'''
LOG.debug('%r.Receive(%r)', self, timeout)
if not self._queue:
self._wake_event.wait(timeout)
if not self._wake_event.isSet():
return
self._queue_lock.acquire()
try:
self._wake_event.clear()
LOG.debug('%r.Receive() queue is %r', self, self._queue)
killed, data = self._queue.pop(0)
LOG.debug('%r.Receive() got killed=%r, data=%r', self, killed, data)
if killed:
raise ChannelError('Channel is closed.')
return data
finally:
self._queue_lock.release()
killed, data = self._queue.get(True, timeout)
except Queue.Empty:
return
LOG.debug('%r.Receive() got killed=%r, data=%r', self, killed, data)
if killed:
raise ChannelError('Channel is closed.')
return data
def __iter__(self):
'''
@ -298,6 +284,9 @@ class BasicStream(object):
class Stream(BasicStream):
_input_buf = ''
_output_buf = ''
def __init__(self, context):
'''
Initialize a new Stream instance.
@ -306,19 +295,13 @@ class Stream(BasicStream):
context: econtext.Context
'''
self._context = context
self._lock = threading.Lock()
self._input_buf = self._output_buf = ''
self._input_buf_lock = threading.Lock()
self._output_buf_lock = threading.Lock()
self._rhmac = hmac.new(context.key, digestmod=sha.new)
self._whmac = self._rhmac.copy()
self._last_handle = 1000L
self._handle_map = {}
self._handle_lock = threading.Lock()
self._func_refs = {}
self._func_ref_lock = threading.Lock()
self._pickler_file = cStringIO.StringIO()
self._pickler = cPickle.Pickler(self._pickler_file, protocol=2)
@ -367,12 +350,12 @@ class Stream(BasicStream):
Returns:
long
'''
self._handle_lock.acquire()
self._lock.acquire()
try:
self._last_handle += 1L
return self._last_handle
finally:
self._handle_lock.release()
return self._last_handle
self._lock.release()
def AddHandleCB(self, fn, handle, persist=True):
'''
@ -385,11 +368,7 @@ class Stream(BasicStream):
'''
LOG.debug('%r.AddHandleCB(%r, %r, persist=%r)',
self, fn, handle, persist)
self._handle_lock.acquire()
try:
self._handle_map[handle] = persist, fn
finally:
self._handle_lock.release()
self._handle_map[handle] = persist, fn
def Receive(self):
'''
@ -465,14 +444,14 @@ class Stream(BasicStream):
'''
LOG.debug('%r.Enqueue(%r, %r)', self, handle, obj)
self._output_buf_lock.acquire()
self._lock.acquire()
try:
encoded = self.Pickle((handle, obj))
msg = struct.pack('>L', len(encoded)) + encoded
self._whmac.update(msg)
self._output_buf += self._whmac.digest() + msg
finally:
self._output_buf_lock.release()
self._lock.release()
self._context.broker.UpdateStream(self, wake=True)
def Disconnect(self):
@ -579,7 +558,7 @@ class LocalStream(Stream):
# Hexed and passed to 'python -c'. It forks, dups 0->100, creates a pipe,
# then execs a new interpreter with a custom argv. CONTEXT_NAME is replaced
# with the context name. Optimized for source size.
# with the context name. Optimized for size.
def _FirstStage():
import os,sys,zlib
R,W=os.pipe()
@ -670,26 +649,24 @@ class Context(object):
reply_handle is the handle on which this function expects its reply.
'''
reply_handle = self._stream.AllocHandle()
reply_event = threading.Event()
container = []
LOG.debug('%r.EnqueueAwaitReply(%r, %r, %r) -> reply handle %d',
self, handle, deadline, data, reply_handle)
queue = Queue.Queue()
def _Receive(killed, data):
LOG.debug('%r._Receive(%r, %r)', self, killed, data)
container.extend([killed, data])
reply_event.set()
queue.put((killed, data))
self._stream.AddHandleCB(_Receive, reply_handle, persist=False)
self._stream.Enqueue(handle, (False, (reply_handle,) + data))
reply_event.wait(deadline)
if not reply_event.isSet():
self.Disconnect()
try:
killed, data = queue.get(True, deadline)
except Queue.Empty:
self._stream.Disconnect()
raise TimeoutError('deadline exceeded.')
killed, data = container
if killed:
raise StreamError('lost connection during call.')

Loading…
Cancel
Save