mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-04 14:25:08 +00:00
fix(display): end the scroll state at scroller-to-static handovers (#716)
A static plugin screen that follows a scroller no longer starts with the ticker's lagging rows on scan-compensated panels, and the 1 Hz loop's second frame is no longer recorded as a ~1 s mid-scroll freeze / Render stall. The display controller calls DisplayManager.end_scroll_for_static_screen() before a static screen's first display() (clears the scan history; _scan_segments passes its frames through in one swap) and set_scrolling_state(False) after it; the scroller's hold stays until then, so late-frame counts are unchanged. A screen's first frame is tagged 'handover': gaps of 250 ms or more before it go to the additive handover_freezes (frame_soak prints 'Handover gaps'), not freezes. The display thread is named display-<plugin id>. The WiFi notice and the schedule-off blank are not covered yet (docs list them as a follow-up). ledpi A B B A soak (20 min each, --preview): main 0.118% / 0.113% late with 6 / 3 freezes; with this and #717 0.107% / 0.104% late, 0 freezes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -59,7 +59,8 @@ class PluginExecutor:
|
||||
self,
|
||||
operation: Callable[[], Any],
|
||||
timeout: Optional[float] = None,
|
||||
plugin_id: Optional[str] = None
|
||||
plugin_id: Optional[str] = None,
|
||||
thread_name: Optional[str] = None
|
||||
) -> Any:
|
||||
"""
|
||||
Execute a plugin operation with timeout.
|
||||
@@ -68,6 +69,8 @@ class PluginExecutor:
|
||||
operation: Function to execute
|
||||
timeout: Timeout in seconds (None = use default)
|
||||
plugin_id: Optional plugin ID for logging
|
||||
thread_name: Name for the thread the operation runs on (None
|
||||
keeps Python's default). Stack dumps list threads by name.
|
||||
|
||||
Returns:
|
||||
Result of operation
|
||||
@@ -93,7 +96,7 @@ class PluginExecutor:
|
||||
result_container['exception'] = e
|
||||
result_container['completed'] = True
|
||||
|
||||
thread = Thread(target=target, daemon=True)
|
||||
thread = Thread(target=target, daemon=True, name=thread_name)
|
||||
thread.start()
|
||||
thread.join(timeout=timeout)
|
||||
|
||||
@@ -223,18 +226,24 @@ class PluginExecutor:
|
||||
'display_mode' in inspect.signature(plugin.display).parameters)
|
||||
has_display_mode = accepts_display_mode
|
||||
|
||||
# Named for the plugin: this thread presents a screen's first
|
||||
# frame, so the frame-timing stall watchdog's stack dumps name it.
|
||||
thread_name = f"display-{plugin_id}"
|
||||
|
||||
# Capture the return value from the plugin's display() method
|
||||
if has_display_mode and display_mode:
|
||||
result = self.execute_with_timeout(
|
||||
lambda: plugin.display(display_mode=display_mode, force_clear=force_clear),
|
||||
timeout=timeout,
|
||||
plugin_id=plugin_id
|
||||
plugin_id=plugin_id,
|
||||
thread_name=thread_name
|
||||
)
|
||||
else:
|
||||
result = self.execute_with_timeout(
|
||||
lambda: plugin.display(force_clear=force_clear),
|
||||
timeout=timeout,
|
||||
plugin_id=plugin_id
|
||||
plugin_id=plugin_id,
|
||||
thread_name=thread_name
|
||||
)
|
||||
|
||||
duration = time.monotonic() - start_time
|
||||
|
||||
Reference in New Issue
Block a user