From b436d2690ae350b6be049add4368d72dcf504dad Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Thu, 28 Jul 2016 05:08:55 +0200 Subject: [PATCH] oslayer/winkeyboardcontrol: fix capture process termination The heartbeat thread needs to be stopped before exit, or with Python 3 the process will deadlock at exit trying to join it. --- plover/oslayer/winkeyboardcontrol.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/plover/oslayer/winkeyboardcontrol.py b/plover/oslayer/winkeyboardcontrol.py index 6f71a0718..bad870e26 100644 --- a/plover/oslayer/winkeyboardcontrol.py +++ b/plover/oslayer/winkeyboardcontrol.py @@ -17,7 +17,6 @@ import multiprocessing import os import threading -import time from ctypes import windll, wintypes @@ -150,12 +149,18 @@ def __init__(self, ppid, atexit): super(HeartBeat, self).__init__() self._ppid = ppid self._atexit = atexit + self._finished = threading.Event() def run(self): while pid_exists(self._ppid): - time.sleep(1) + if self._finished.wait(1): + break self._atexit() + def stop(self): + self._finished.set() + self.join() + class KeyboardCaptureProcess(multiprocessing.Process): @@ -221,7 +226,7 @@ def _open_key(rights): def run(self): - heartbeat = HeartBeat(self._ppid, self.stop) + heartbeat = HeartBeat(self._ppid, self._send_quit) heartbeat.start() import atexit @@ -292,6 +297,13 @@ def low_level_handler(code, wparam, lparam): windll.user32.TranslateMessage(ctypes.byref(msg)) windll.user32.DispatchMessageW(ctypes.byref(msg)) + heartbeat.stop() + + def _send_quit(self): + windll.user32.PostThreadMessageW(self._tid, + 0x0012, # WM_QUIT + 0, 0) + def start(self): self.daemon = True super(KeyboardCaptureProcess, self).start() @@ -299,9 +311,7 @@ def start(self): def stop(self): if self.is_alive(): - windll.user32.PostThreadMessageW(self._tid, - 0x0012, # WM_QUIT - 0, 0) + self._send_quit() self.join() # Wake up capture thread, so it gets a chance to check if it must stop. self._queue.put((None, None)) @@ -341,9 +351,9 @@ def run(self): (self.key_down if pressed else self.key_up)(key) def cancel(self): + self._finished.set() self._proc.stop() if self.is_alive(): - self._finished.set() self.join() def suppress_keyboard(self, suppressed_keys=()):