Final batch of code stability updates before anouther bout of extended testing. Still plenty to go, but making progress.
This commit is contained in:
parent
64e79f6945
commit
dda84b9905
@ -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):
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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}
|
||||||
|
@ -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)
|
||||||
|
@ -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 = ''
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user