Final batch of code stability updates before anouther bout of extended testing. Still plenty to go, but making progress.

This commit is contained in:
Storm Dragon 2025-06-20 03:34:50 -04:00
parent 64e79f6945
commit dda84b9905
7 changed files with 48 additions and 15 deletions

View File

@ -4,7 +4,12 @@
# Fenrir TTY screen reader # Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers. # By Chrys, Storm Dragon, and contributers.
from fenrirscreenreader.commands.vmenu_navigation.vmenu_search_base import VMenuSearchCommand import importlib.util
import os
_spec = importlib.util.spec_from_file_location("vmenu_search_base", os.path.join(os.path.dirname(__file__), "vmenu_search_base.py"))
_module = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_module)
VMenuSearchCommand = _module.VMenuSearchCommand
class command(VMenuSearchCommand): class command(VMenuSearchCommand):
def __init__(self): def __init__(self):

View File

@ -84,11 +84,9 @@ class commandManager():
fileName = fileName.split('/')[-1] fileName = fileName.split('/')[-1]
if fileName.startswith('__'): if fileName.startswith('__'):
continue continue
try: # Check if command already exists to prevent duplicate loading
if self.env['commands'][section][fileName.upper()] != None: if fileName.upper() in self.env['commands'][section] and self.env['commands'][section][fileName.upper()] is not None:
continue continue
except Exception as e:
pass
if fileExtension.lower() == '.py': if fileExtension.lower() == '.py':
command_mod = module_utils.importModule(fileName, command) command_mod = module_utils.importModule(fileName, command)
self.env['commands'][section][fileName.upper()] = command_mod.command() self.env['commands'][section][fileName.upper()] = command_mod.command()

View File

@ -15,7 +15,7 @@ from ctypes import c_bool
class eventManager(): class eventManager():
def __init__(self): def __init__(self):
self.running = Value(c_bool, True) self.running = Value(c_bool, True)
self._eventQueue = Queue() # multiprocessing.Queue() self._eventQueue = Queue(maxsize=100) # Bounded queue to prevent memory exhaustion
self.cleanEventQueue() self.cleanEventQueue()
def initialize(self, environment): def initialize(self, environment):
self.env = environment self.env = environment
@ -85,8 +85,16 @@ class eventManager():
return False return False
if event == fenrirEventType.Ignore: if event == fenrirEventType.Ignore:
return False return False
if self.getEventQueueSize() > 50: # Use bounded queue - if full, this will block briefly or drop older events
if not event in [fenrirEventType.ScreenUpdate, fenrirEventType.HeartBeat]: try:
self.cleanEventQueue() self._eventQueue.put({"Type":event,"Data":data}, timeout=0.1)
self._eventQueue.put({"Type":event,"Data":data}) except Exception as e:
# Queue full - drop oldest event and add new one for critical events
if event in [fenrirEventType.ScreenUpdate, fenrirEventType.KeyboardInput]:
try:
self._eventQueue.get_nowait() # Remove oldest
self._eventQueue.put({"Type":event,"Data":data}, timeout=0.1)
except:
pass # If still can't add, drop the event
# For non-critical events, just drop them if queue is full
return True return True

View File

@ -30,11 +30,12 @@ class memoryManager():
if not self.listStorageValid(name): if not self.listStorageValid(name):
return return
if self.listStorage[name]['maxLength'] == None: if self.listStorage[name]['maxLength'] == None:
self.listStorage[name]['list'] = [value] + self.listStorage[name]['list'] # Fallback: if maxLength is still None, apply default limit of 1000
self.listStorage[name]['list'] = [value] + self.listStorage[name]['list'][:999]
else: else:
self.listStorage[name]['list'] = [value] + self.listStorage[name]['list'][:self.listStorage[name]['maxLength'] -1] self.listStorage[name]['list'] = [value] + self.listStorage[name]['list'][:self.listStorage[name]['maxLength'] -1]
self.listStorage[name]['index'] = 0 self.listStorage[name]['index'] = 0
def addIndexList(self, name, maxLength = None, currList = [], currIndex = -1): def addIndexList(self, name, maxLength = 1000, currList = [], currIndex = -1):
if len(currList) != 0 and (currIndex == -1): if len(currList) != 0 and (currIndex == -1):
currIndex = 0 currIndex = 0
self.listStorage[name] = {'list': currList, 'index': currIndex, 'maxLength': maxLength} self.listStorage[name] = {'list': currList, 'index': currIndex, 'maxLength': maxLength}

View File

@ -29,9 +29,9 @@ class processManager():
# pass # pass
#except: #except:
# pass # pass
proc.join() proc.join(timeout=5.0) # Timeout to prevent hanging shutdown
for t in self._Threads: for t in self._Threads:
t.join() t.join(timeout=5.0) # Timeout to prevent hanging shutdown
def heartBeatTimer(self, active): def heartBeatTimer(self, active):
try: try:
time.sleep(0.5) time.sleep(0.5)

View File

@ -62,6 +62,18 @@ class driver(soundDriver):
return return
if self.soundType == 'file': if self.soundType == 'file':
self.proc.kill() self.proc.kill()
try:
self.proc.wait(timeout=1.0) # Wait for process to finish to prevent zombies
except subprocess.TimeoutExpired:
pass # Process already terminated
except Exception as e:
pass # Handle any other wait errors
if self.soundType == 'frequence': if self.soundType == 'frequence':
self.proc.kill() self.proc.kill()
try:
self.proc.wait(timeout=1.0) # Wait for process to finish to prevent zombies
except subprocess.TimeoutExpired:
pass # Process already terminated
except Exception as e:
pass # Handle any other wait errors
self.soundType = '' self.soundType = ''

View File

@ -10,6 +10,7 @@ from threading import Thread, Lock
from queue import Queue, Empty from queue import Queue, Empty
import shlex import shlex
from subprocess import Popen from subprocess import Popen
import subprocess
from fenrirscreenreader.core.speechDriver import speechDriver from fenrirscreenreader.core.speechDriver import speechDriver
class speakQueue(Queue): class speakQueue(Queue):
@ -77,10 +78,18 @@ class driver(speechDriver):
if self.proc: if self.proc:
try: try:
self.proc.terminate() self.proc.terminate()
# Wait for process to finish to prevent zombies
try:
self.proc.wait(timeout=1.0)
except subprocess.TimeoutExpired:
# If terminate didn't work, force kill
self.proc.kill()
self.proc.wait(timeout=1.0)
except Exception as e: except Exception as e:
self.env['runtime']['debug'].writeDebugOut('speechDriver:Cancel:self.proc.terminate():' + str(e),debug.debugLevel.WARNING) self.env['runtime']['debug'].writeDebugOut('speechDriver:Cancel:self.proc.terminate():' + str(e),debug.debugLevel.WARNING)
try: try:
self.proc.kill() self.proc.kill()
self.proc.wait(timeout=1.0) # Wait after kill to prevent zombies
except Exception as e: except Exception as e:
self.env['runtime']['debug'].writeDebugOut('speechDriver:Cancel:self.proc.kill():' + str(e),debug.debugLevel.WARNING) self.env['runtime']['debug'].writeDebugOut('speechDriver:Cancel:self.proc.kill():' + str(e),debug.debugLevel.WARNING)
self.proc = None self.proc = None