- ~ThreadManager() never stopped worker threads before freeing the
global context. If Teardown() wasn't reached before process exit
(e.g. an early return between Init() and a caller's shutdown path),
the still-running threads kept touching freed mutexes/queues/condvars,
causing intermittent crashes on exit. The destructor now tears down
if still initialized.
- Teardown() silently leaked any non-cancellable task still sitting in
a queue (global or per-thread) at shutdown time - such tasks were
never run nor released, since nothing drains those queues once the
worker threads have been marked cancelled/joined. Now every queued
task is properly cancelled-or-warned and released.
- Added an assert against a divide-by-zero in EnqueueTask's round-robin
fallback, which would trigger if Init() were ever called with zero
compute threads.
- Removed Task::id()/Kind() and ThreadManager::TryCancelTask(), which
were unused dead code (TryCancelTask was a no-op with no callers).
- Fixed a stale comment on EnqueueTaskOnThread referencing a parameter
that doesn't exist, and an auto-typed ternary that misleadingly read
like a deque array copy (it's a pointer, not a copy).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4QAoxV2KY7ek4PcZw3WvY
Useful for things that should be run ASAP even if the threadpool is full,
at a small extra cost. (Not recommended for very small tasks).
Considering using this to resolve the deadlocks in #16802.
Moves ThreadPool teardown to retro_unload_game. Gives ThreadPool threads some breathing room to terminate before game load starts spamming it with tasks.