Skip to content

Commit 8e9c7a4

Browse files
committed
Improve application shutdown handling
1 parent c735bdc commit 8e9c7a4

File tree

3 files changed

+40
-7
lines changed

3 files changed

+40
-7
lines changed

library/scheduler.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def decorator(func):
4242
def async_func(*args, **kwargs):
4343
""" create an asynchronous function to wrap around our thread """
4444
func_hl = threading.Thread(target=func, name=threadname, args=args, kwargs=kwargs)
45+
func_hl.daemon = True
4546
func_hl.start()
4647
return func_hl
4748

library/smartmonitor_runtime.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
_RUNTIME_READY = True
1919
_RUNTIME_DISABLED_REASON: str | None = None
2020
_DISK_IO_SAMPLE: tuple[float, float] | None = None
21+
_RUNTIME_THREADS: list[threading.Thread] = []
2122
_THEME_DEFAULT_TAGS: dict[str, dict[str, int]] = {
2223
"theme_science fiction.dat": {
2324
"CPU_PERCENT": 3,
@@ -585,6 +586,7 @@ def _metrics_worker():
585586

586587

587588
def start():
589+
global _RUNTIME_THREADS
588590
if not _RUNTIME_READY:
589591
if _RUNTIME_DISABLED_REASON:
590592
logger.warning("SmartMonitor runtime workers are disabled: %s", _RUNTIME_DISABLED_REASON)
@@ -594,8 +596,22 @@ def start():
594596

595597
logger.info("Starting SmartMonitor HID runtime mode")
596598

597-
time_thread = threading.Thread(target=_time_worker, name="SmartMonitor_Time", daemon=False)
598-
metrics_thread = threading.Thread(target=_metrics_worker, name="SmartMonitor_Metrics", daemon=False)
599+
time_thread = threading.Thread(target=_time_worker, name="SmartMonitor_Time", daemon=True)
600+
metrics_thread = threading.Thread(target=_metrics_worker, name="SmartMonitor_Metrics", daemon=True)
599601
time_thread.start()
600602
metrics_thread.start()
601-
return [time_thread, metrics_thread]
603+
_RUNTIME_THREADS = [time_thread, metrics_thread]
604+
return list(_RUNTIME_THREADS)
605+
606+
607+
def stop(timeout: float = 3.0):
608+
import library.scheduler as scheduler
609+
610+
scheduler.STOPPING = True
611+
deadline = time.monotonic() + max(0.0, timeout)
612+
for thread in list(_RUNTIME_THREADS):
613+
remaining = max(0.0, deadline - time.monotonic())
614+
if remaining <= 0:
615+
break
616+
if thread.is_alive():
617+
thread.join(remaining)

main.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
MAIN_DIRECTORY = str(Path(__file__).parent.resolve()) + "/"
7373

7474
if __name__ == "__main__":
75+
_STOP_REQUESTED = False
7576

7677
# Apply system locale to this program
7778
locale.setlocale(locale.LC_ALL, '')
@@ -91,6 +92,11 @@ def wait_for_empty_queue(timeout: int = 5):
9192
logger.debug("(Waited %.1fs)" % wait_time)
9293

9394
def clean_stop(tray_icon=None):
95+
global _STOP_REQUESTED
96+
if _STOP_REQUESTED:
97+
return
98+
_STOP_REQUESTED = True
99+
94100
# Turn screen and LEDs off before stopping
95101
if not smartmonitor_runtime.is_enabled():
96102
display.turn_off()
@@ -99,15 +105,25 @@ def clean_stop(tray_icon=None):
99105
# Instead, ask the scheduler to empty the action queue before stopping
100106
scheduler.STOPPING = True
101107

102-
if not smartmonitor_runtime.is_enabled():
108+
if smartmonitor_runtime.is_enabled():
109+
smartmonitor_runtime.stop(timeout=3.0)
110+
try:
111+
display.lcd.closeSerial()
112+
except Exception:
113+
pass
114+
else:
103115
# Waiting for all pending request to be sent to display
104116
wait_for_empty_queue(5)
105-
else:
106-
display.lcd.closeSerial()
107117

108118
# Remove tray icon just before exit
109119
if tray_icon:
110-
tray_icon.visible = False
120+
try:
121+
tray_icon.stop()
122+
except Exception:
123+
try:
124+
tray_icon.visible = False
125+
except Exception:
126+
pass
111127

112128
# We force the exit to avoid waiting for other scheduled tasks: they may have a long delay!
113129
try:

0 commit comments

Comments
 (0)