chatgui: fix rlottie thread hang on Windows shutdown

Root cause: librlottie RleTaskScheduler creates 32 worker threads on first
lottie_animation_from_data call. These pthreads wait in WaitForMultipleObjects(INFINITE)
and never exit. On MinGW, exit()/pthread_join blocks forever.

Changes:
- messagelist: s_icons moved to file-static; cleanupAnimations() clears them,
  calling lottie_animation_destroy BEFORE static destruction
- mainwindow: ~MainWindow calls MessageList::cleanupAnimations() after node stop
- main: ShutdownSentinel counts threads at exit; if >4 remaining, calls
  ExitProcess(0) to bypass CRT pthread_join hang
- main: if rlottie properly shuts down (<=4 threads), normal return (no ExitProcess)
This commit is contained in:
Evgeny committed 2026-07-24 14:54:12 +03:00
1 parent 74c6b0d102
commit 73be79d204
4 files changed
+35 -1

No files matched your search

+22
View File
@@ -5,6 +5,7 @@
#include <cstdio>
#ifdef _WIN32
#include <windows.h>
#include <tlhelp32.h>
#endif
#include "mainwindow.h"
#include "../db/db_manager.h"
@@ -15,6 +16,19 @@
#ifdef _WIN32
static UtunNode* g_ctrl_node = nullptr;
static DWORD count_threads(void) {
DWORD pid = GetCurrentProcessId(), count = 0;
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (snap == INVALID_HANDLE_VALUE) return 0;
THREADENTRY32 te = { sizeof(te) };
if (Thread32First(snap, &te)) {
do { if (te.th32OwnerProcessID == pid) count++; }
while (Thread32Next(snap, &te));
}
CloseHandle(snap);
return count;
}
static BOOL WINAPI console_ctrl_handler(DWORD dwCtrlType) {
if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
if (g_ctrl_node) g_ctrl_node->requestStop();
@@ -27,6 +41,14 @@ static BOOL WINAPI console_ctrl_handler(DWORD dwCtrlType) {
static struct ShutdownSentinel {
~ShutdownSentinel() {
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "main: static destructors done");
#ifdef _WIN32
DWORD threads = count_threads();
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "main: threads at exit=%lu", (unsigned long)threads);
if (threads > 4) {
DEBUG_WARN(DEBUG_CATEGORY_DEBUG, "main: %lu hanging threads, ExitProcess", (unsigned long)threads);
ExitProcess(0);
}
#endif
}
} g_shutdown_sentinel;