issue #156: prevent Latch.close() triggering spurious wakeups

pull/167/head
David Wilson 6 years ago
parent 18e2977baf
commit 526b0a514b

@ -889,11 +889,17 @@ Latch.close()
~~~~~~~~~~~
:py:meth:`mitogen.core.Latch.close` acquires `lock`, sets `closed` to
:py:data:`True`, then writes a byte to every socket in `sleeping`. Per above,
on waking from sleep, after removing itself from `sleeping`, each sleeping
thread tests if `closed` is :py:data:`True`, and if so throws
:py:data:`True`, then writes a byte to every `sleeping[waking]` socket, while
incrementing `waking`, until no more unwoken sockets exist. Per above, on
waking from sleep, after removing itself from `sleeping`, each sleeping thread
tests if `closed` is :py:data:`True`, and if so throws
:py:class:`mitogen.core.LatchError`.
It is necessary to ensure at most one byte is delivered on each socket, even if
the latch is being torn down, as the sockets outlive the scope of a single
latch, and must never have extraneous data buffered on them, as this will cause
unexpected wakeups if future latches sleep on the same thread.
Latch.get()
~~~~~~~~~~~
@ -930,6 +936,11 @@ item.
`waking`, then pops and returns the first item in `queue` that is
guaranteed to exist.
It is paramount that in every case, if :py:func:`select.select` indicates a
byte was written to the socket, that the byte is read away. The socket is
reused by subsequent latches sleeping on the same thread, and unexpected
wakeups are triggered if extraneous data remains buffered on the socket.
.. rubric:: Footnotes

@ -918,8 +918,9 @@ class Latch(object):
self._lock.acquire()
try:
self.closed = True
for wsock in self._sleeping:
self._wake(wsock)
while self._waking < len(self._sleeping):
self._wake(self._sleeping[self._waking])
self._waking += 1
finally:
self._lock.release()
@ -957,13 +958,13 @@ class Latch(object):
self._lock.acquire()
try:
self._sleeping.remove(_tls.wsock)
if self.closed:
raise LatchError()
if not rfds:
raise TimeoutError()
self._waking -= 1
if _tls.rsock.recv(2) != '\x7f':
raise LatchError('internal error: received >1 wakeups')
self._waking -= 1
if self.closed:
raise LatchError()
try:
_vv and IOLOG.debug('%r.get() wake -> %r', self, self._queue[0])
return self._queue.pop(0)

Loading…
Cancel
Save