Preparing for new tagged release.
This commit is contained in:
@@ -13,6 +13,76 @@ from fenrirscreenreader.core import debug
|
|||||||
from fenrirscreenreader.core.eventData import FenrirEventType
|
from fenrirscreenreader.core.eventData import FenrirEventType
|
||||||
|
|
||||||
|
|
||||||
|
# Standalone functions for multiprocessing (cannot be instance methods)
|
||||||
|
def _heart_beat_timer(running):
|
||||||
|
"""
|
||||||
|
Standalone heartbeat timer function for multiprocessing.
|
||||||
|
Returns current timestamp after a short sleep.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
time.sleep(0.5)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ProcessManager _heart_beat_timer: Error during sleep: {e}")
|
||||||
|
return time.time()
|
||||||
|
|
||||||
|
|
||||||
|
def _custom_event_worker_process(
|
||||||
|
running, event_queue, function, pargs=None, run_once=False
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Standalone worker function for custom events in multiprocessing.
|
||||||
|
Cannot use instance methods due to pickle limitations with self.env.
|
||||||
|
"""
|
||||||
|
if not callable(function):
|
||||||
|
return
|
||||||
|
while running.value:
|
||||||
|
try:
|
||||||
|
if pargs:
|
||||||
|
function(running, event_queue, pargs)
|
||||||
|
else:
|
||||||
|
function(running, event_queue)
|
||||||
|
except Exception as e:
|
||||||
|
# Cannot use DebugManager in multiprocess context
|
||||||
|
print(
|
||||||
|
f"ProcessManager:_custom_event_worker_process:function("
|
||||||
|
f"{function}):{e}"
|
||||||
|
)
|
||||||
|
if run_once:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def _simple_event_worker_process(
|
||||||
|
running, event_queue, event, function, pargs=None, run_once=False
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Standalone worker function for simple events in multiprocessing.
|
||||||
|
Cannot use instance methods due to pickle limitations with self.env.
|
||||||
|
"""
|
||||||
|
if not isinstance(event, FenrirEventType):
|
||||||
|
return
|
||||||
|
if not callable(function):
|
||||||
|
return
|
||||||
|
while running.value:
|
||||||
|
data = None
|
||||||
|
try:
|
||||||
|
if pargs:
|
||||||
|
data = function(running, pargs)
|
||||||
|
else:
|
||||||
|
data = function(running)
|
||||||
|
except Exception as e:
|
||||||
|
# Cannot use DebugManager in multiprocess context
|
||||||
|
print(
|
||||||
|
f"ProcessManager:_simple_event_worker_process:function("
|
||||||
|
f"{function}):{e}"
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
event_queue.put({"Type": event, "data": data}, timeout=0.1)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ProcessManager: Failed to put event to queue: {e}")
|
||||||
|
if run_once:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
class ProcessManager:
|
class ProcessManager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._Processes = []
|
self._Processes = []
|
||||||
@@ -23,7 +93,7 @@ class ProcessManager:
|
|||||||
self.running = self.env["runtime"]["EventManager"].get_running()
|
self.running = self.env["runtime"]["EventManager"].get_running()
|
||||||
self.add_simple_event_thread(
|
self.add_simple_event_thread(
|
||||||
FenrirEventType.heart_beat,
|
FenrirEventType.heart_beat,
|
||||||
self.heart_beat_timer,
|
_heart_beat_timer,
|
||||||
multiprocess=True,
|
multiprocess=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -60,8 +130,8 @@ class ProcessManager:
|
|||||||
original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
|
original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||||
if multiprocess:
|
if multiprocess:
|
||||||
t = Process(
|
t = Process(
|
||||||
target=self.custom_event_worker_thread,
|
target=_custom_event_worker_process,
|
||||||
args=(event_queue, function, pargs, run_once),
|
args=(self.running, event_queue, function, pargs, run_once),
|
||||||
)
|
)
|
||||||
self._Processes.append(t)
|
self._Processes.append(t)
|
||||||
else: # use thread instead of process
|
else: # use thread instead of process
|
||||||
@@ -78,9 +148,11 @@ class ProcessManager:
|
|||||||
):
|
):
|
||||||
original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
|
original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||||
if multiprocess:
|
if multiprocess:
|
||||||
|
# Get event queue reference before creating process
|
||||||
|
event_queue = self.env["runtime"]["EventManager"].get_event_queue()
|
||||||
t = Process(
|
t = Process(
|
||||||
target=self.simple_event_worker_thread,
|
target=_simple_event_worker_process,
|
||||||
args=(event, function, pargs, run_once),
|
args=(self.running, event_queue, event, function, pargs, run_once),
|
||||||
)
|
)
|
||||||
self._Processes.append(t)
|
self._Processes.append(t)
|
||||||
else:
|
else:
|
||||||
@@ -106,12 +178,13 @@ class ProcessManager:
|
|||||||
else:
|
else:
|
||||||
function(self.running, event_queue)
|
function(self.running, event_queue)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
# Cannot use DebugManager in multiprocess context due to
|
||||||
|
# pickle limitations with file handles
|
||||||
|
print(
|
||||||
"ProcessManager:custom_event_worker_thread:function("
|
"ProcessManager:custom_event_worker_thread:function("
|
||||||
+ str(function)
|
+ str(function)
|
||||||
+ "):"
|
+ "):"
|
||||||
+ str(e),
|
+ str(e)
|
||||||
debug.DebugLevel.ERROR,
|
|
||||||
)
|
)
|
||||||
if run_once:
|
if run_once:
|
||||||
break
|
break
|
||||||
@@ -131,12 +204,13 @@ class ProcessManager:
|
|||||||
else:
|
else:
|
||||||
data = function(self.running)
|
data = function(self.running)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
# Cannot use DebugManager in multiprocess context due to
|
||||||
|
# pickle limitations with file handles
|
||||||
|
print(
|
||||||
"ProcessManager:simple_event_worker_thread:function("
|
"ProcessManager:simple_event_worker_thread:function("
|
||||||
+ str(function)
|
+ str(function)
|
||||||
+ "):"
|
+ "):"
|
||||||
+ str(e),
|
+ str(e)
|
||||||
debug.DebugLevel.ERROR,
|
|
||||||
)
|
)
|
||||||
self.env["runtime"]["EventManager"].put_to_event_queue(event, data)
|
self.env["runtime"]["EventManager"].put_to_event_queue(event, data)
|
||||||
if run_once:
|
if run_once:
|
||||||
|
|||||||
@@ -4,5 +4,5 @@
|
|||||||
# Fenrir TTY screen reader
|
# Fenrir TTY screen reader
|
||||||
# By Chrys, Storm Dragon, and contributors.
|
# By Chrys, Storm Dragon, and contributors.
|
||||||
|
|
||||||
version = "2025.10.17"
|
version = "2025.11.23"
|
||||||
code_name = "master"
|
code_name = "master"
|
||||||
|
|||||||
@@ -20,8 +20,10 @@ class driver(remoteDriver):
|
|||||||
|
|
||||||
def initialize(self, environment):
|
def initialize(self, environment):
|
||||||
self.env = environment
|
self.env = environment
|
||||||
|
# Use threading instead of multiprocessing to avoid pickle issues
|
||||||
|
# with self.env (which contains unpicklable file handles)
|
||||||
self.env["runtime"]["ProcessManager"].add_custom_event_thread(
|
self.env["runtime"]["ProcessManager"].add_custom_event_thread(
|
||||||
self.watch_dog, multiprocess=True
|
self.watch_dog, multiprocess=False
|
||||||
)
|
)
|
||||||
|
|
||||||
def watch_dog(self, active, event_queue):
|
def watch_dog(self, active, event_queue):
|
||||||
|
|||||||
@@ -20,8 +20,10 @@ class driver(remoteDriver):
|
|||||||
|
|
||||||
def initialize(self, environment):
|
def initialize(self, environment):
|
||||||
self.env = environment
|
self.env = environment
|
||||||
|
# Use threading instead of multiprocessing to avoid pickle issues
|
||||||
|
# with self.env (which contains unpicklable file handles)
|
||||||
self.env["runtime"]["ProcessManager"].add_custom_event_thread(
|
self.env["runtime"]["ProcessManager"].add_custom_event_thread(
|
||||||
self.watch_dog, multiprocess=True
|
self.watch_dog, multiprocess=False
|
||||||
)
|
)
|
||||||
|
|
||||||
def watch_dog(self, active, event_queue):
|
def watch_dog(self, active, event_queue):
|
||||||
|
|||||||
@@ -126,8 +126,10 @@ class driver(screenDriver):
|
|||||||
"default", # fontfamily
|
"default", # fontfamily
|
||||||
]
|
]
|
||||||
) # end attribute )
|
) # end attribute )
|
||||||
|
# Use threading instead of multiprocessing to avoid pickle issues
|
||||||
|
# with self.env (which contains unpicklable file handles)
|
||||||
self.env["runtime"]["ProcessManager"].add_custom_event_thread(
|
self.env["runtime"]["ProcessManager"].add_custom_event_thread(
|
||||||
self.update_watchdog, multiprocess=True
|
self.update_watchdog, multiprocess=False
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_curr_screen(self):
|
def get_curr_screen(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user