ff90824247
* fix(wallet): prevent exit-hang on Windows from detached Tor/I2P threads Embedded Tor and embedded I2P each ran on a background std::thread that was .detach()'d at startup. The teardown paths (CTorEmbedded::Stop, CI2PEmbedded::Stop) only flipped a running-flag — they did not signal the thread to exit, and on Windows there is no signal mechanism in tor_api 0.4.x. Result on Windows: when the user closed the wallet, Shutdown() completed its bookkeeping and main() returned 0, but the process could not exit because the detached thread was still in the Tor event loop / i2pd io_context. End Task (TerminateProcess) was the only escape; the GUI appeared completely stuck. Fixes: - tor_embedded.h/.cpp: keep the Tor thread handle; Stop() now raise(SIGTERM) on Linux, then joins the thread with a 5s timeout, then TerminateThread (Win) / pthread_cancel + pthread_join (Linux) as a last resort. - i2p_embedded.h/.cpp: same pattern — capture the bootstrap thread and join it in Stop() with a 5s timeout fallback. - init.cpp Shutdown(): spawn a 30s watchdog thread that calls ExitProcess(1) if the graceful teardown takes too long. Belt-and-suspenders against any future deadlock in the exit path. - trianglesgui.cpp closeEvent(): second close attempt while the first exit is still running immediately calls ExitProcess(2) / _exit(2). User escape hatch when the graceful exit hangs. All non-consensus (threading/process lifecycle only). Build via CI; not local. Notes: notes/wallet-close-hang-fix-2026-07-07.md * fix(i2p): drop leftover .detach() that broke build (lambda now joinable) * fix(i2p): clean up after .detach() removal (trailing comment, blank line) * fix(tor): MINGW std::thread is pthread-based, use pthread_cancel/join on MINGW MINGW std::thread::native_handle_type is unsigned long long (pthread_t emulation), not HANDLE. Mixing pthread handles with Win32 WaitForSingleObject/TerminateThread fails to compile on MINGW with 'invalid conversion' errors. Use the same pthread_cancel/pthread_join path on Linux and MINGW; keep TerminateThread only for MSVC builds where native_handle() returns a real Win32 HANDLE. --------- Co-authored-by: krystie <krystie>