From 64e79f69452f4cf5063353659b5649d2d22507fd Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Fri, 20 Jun 2025 03:10:07 -0400 Subject: [PATCH] Code cleanup, make sure race conditions can't happen, at least in theory. --- .../remoteDriver/unixDriver.py | 36 +++++++++++-------- .../soundDriver/gstreamerDriver.py | 3 ++ .../speechDriver/genericDriver.py | 21 ++++++----- 3 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/fenrirscreenreader/remoteDriver/unixDriver.py b/src/fenrirscreenreader/remoteDriver/unixDriver.py index 3a0a2c53..a56724ce 100644 --- a/src/fenrirscreenreader/remoteDriver/unixDriver.py +++ b/src/fenrirscreenreader/remoteDriver/unixDriver.py @@ -45,21 +45,27 @@ class driver(remoteDriver): continue if self.fenrirSock in r: client_sock, client_addr = self.fenrirSock.accept() - try: - rawdata = client_sock.recv(8129) - except Exception as e: - self.env['runtime']['debug'].writeDebugOut('unixDriver watchDog: Error receiving data from client: ' + str(e), debug.debugLevel.ERROR) - try: - data = rawdata.decode("utf-8").rstrip().lstrip() - eventQueue.put({"Type":fenrirEventType.RemoteIncomming, - "Data": data - }) - except Exception as e: - self.env['runtime']['debug'].writeDebugOut('unixDriver watchDog: Error decoding/queuing data: ' + str(e), debug.debugLevel.ERROR) - try: - client_sock.close() - except Exception as e: - self.env['runtime']['debug'].writeDebugOut('unixDriver watchDog: Error closing client socket: ' + str(e), debug.debugLevel.ERROR) + # Ensure client socket is always closed to prevent resource leaks + try: + try: + rawdata = client_sock.recv(8129) + except Exception as e: + self.env['runtime']['debug'].writeDebugOut('unixDriver watchDog: Error receiving data from client: ' + str(e), debug.debugLevel.ERROR) + rawdata = b'' # Set default empty data if recv fails + + try: + data = rawdata.decode("utf-8").rstrip().lstrip() + eventQueue.put({"Type":fenrirEventType.RemoteIncomming, + "Data": data + }) + except Exception as e: + self.env['runtime']['debug'].writeDebugOut('unixDriver watchDog: Error decoding/queuing data: ' + str(e), debug.debugLevel.ERROR) + finally: + # Always close client socket, even if data processing fails + try: + client_sock.close() + except Exception as e: + self.env['runtime']['debug'].writeDebugOut('unixDriver watchDog: Error closing client socket: ' + str(e), debug.debugLevel.ERROR) if self.fenrirSock: self.fenrirSock.close() self.fenrirSock = None diff --git a/src/fenrirscreenreader/soundDriver/gstreamerDriver.py b/src/fenrirscreenreader/soundDriver/gstreamerDriver.py index 0450ff03..42926e37 100644 --- a/src/fenrirscreenreader/soundDriver/gstreamerDriver.py +++ b/src/fenrirscreenreader/soundDriver/gstreamerDriver.py @@ -57,6 +57,9 @@ class driver(soundDriver): return self.cancel() self.mainloop.quit() + # Wait for the GLib MainLoop thread to finish to prevent shutdown races + if hasattr(self, 'thread') and self.thread.is_alive(): + self.thread.join(timeout=2.0) # 2 second timeout to prevent hanging def _onPlayerMessage(self, bus, message): if not self._initialized: diff --git a/src/fenrirscreenreader/speechDriver/genericDriver.py b/src/fenrirscreenreader/speechDriver/genericDriver.py index 592aefe5..e841218a 100644 --- a/src/fenrirscreenreader/speechDriver/genericDriver.py +++ b/src/fenrirscreenreader/speechDriver/genericDriver.py @@ -73,17 +73,20 @@ class driver(speechDriver): return self.clear_buffer() self.lock.acquire(True) - if self.proc: - try: - self.proc.terminate() - except Exception as e: - self.env['runtime']['debug'].writeDebugOut('speechDriver:Cancel:self.proc.terminate():' + str(e),debug.debugLevel.WARNING) + try: + if self.proc: try: - self.proc.kill() + self.proc.terminate() except Exception as e: - self.env['runtime']['debug'].writeDebugOut('speechDriver:Cancel:self.proc.kill():' + str(e),debug.debugLevel.WARNING) - self.proc = None - self.lock.release() + self.env['runtime']['debug'].writeDebugOut('speechDriver:Cancel:self.proc.terminate():' + str(e),debug.debugLevel.WARNING) + try: + self.proc.kill() + except Exception as e: + self.env['runtime']['debug'].writeDebugOut('speechDriver:Cancel:self.proc.kill():' + str(e),debug.debugLevel.WARNING) + self.proc = None + finally: + # Ensure lock is always released, even if process termination fails + self.lock.release() def setCallback(self, callback): print('SpeechDummyDriver: setCallback')