From 807cbef9caa374bbf96ac90a81221388345e832d Mon Sep 17 00:00:00 2001 From: David Wilson Date: Sun, 24 Feb 2019 20:09:48 +0000 Subject: [PATCH] core: wake Latch outside of lock. Given: - thread A asleep in Latch._get_sleep() - thread B calling Latch.put() Previously, - B takes lock, - B wakes socket by dropping GIL and writing to it - A wakes from poll(), acquires GIL only to find Latch._lock is held - A drops GIL, sleeps on futex() for _lock - B wakes, acquires GIL, releases _lock - A wakes from futex(), acquires lock Now, - B takes lock, updates state, releases lock - B wakes socket by droppping GIL and writing to it - A wakes from poll(), acquires GIL and _lock - Everyone lives happily ever after. --- mitogen/core.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mitogen/core.py b/mitogen/core.py index 56e9e9eb..ea55f7bb 100644 --- a/mitogen/core.py +++ b/mitogen/core.py @@ -2489,17 +2489,20 @@ class Latch(object): raise LatchError() self._queue.append(obj) + wsock = None if self._waking < len(self._sleeping): wsock, cookie = self._sleeping[self._waking] self._waking += 1 _vv and IOLOG.debug('%r.put() -> waking wfd=%r', self, wsock.fileno()) - self._wake(wsock, cookie) elif self.notify: self.notify(self) finally: self._lock.release() + if wsock: + self._wake(wsock, cookie) + def _wake(self, wsock, cookie): written, disconnected = io_op(os.write, wsock.fileno(), cookie) assert written == len(cookie) and not disconnected