The core no longer sleeps to pace itself: the frontend runs retro_run at
its own rate, so the frame throttle, the idle-vblank delay and the real
clock sync event (and its core option) are gone, and a stepping CPU hands
straight back instead of waiting 2 ms. Waits that polled now park on a
lock-free eventcount through Common/Thread/ParkingLot and are woken by
whoever changes the state: a paused GL emu thread, which also queues a
marker behind its last frame so pausing runs the render queue up to it
instead of polling; async I/O results; the software renderer when its
queue is full; Vulkan pipeline compiles; and debugger requests once
stepping ends. Boot joins the loader thread, cache shutdown joins its
read-ahead thread, and the slow-I/O simulation is removed.
The path browser, the HTTP and WebSocket servers, the Windows console and
the game info cache are left out of the core build. libretro/test gains
lrgltest, which drives the GL backend on a surfaceless EGL context through
every path that pauses or stops the emu thread; run.sh and the image
checks CI job run it on llvmpipe.
The notify_one chain (each waiter wakes exactly one more) was correct
but fragile and non-obvious. notify_all is simpler and just as cheap
here since Arrive() is not a hot path.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4QAoxV2KY7ek4PcZw3WvY
SimpleParallelTask/LoopRangeTask never overrode Cancellable(), so a
ThreadManager::Teardown() racing with an in-flight parallel loop would
drop them without ever calling counter_->Count(), leaving anyone
blocked in WaitableCounter::Wait() stuck forever. Cancel() now counts
down the same as a normal completion.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4QAoxV2KY7ek4PcZw3WvY
- ~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
It's better to finish rendering the frame and have the texture ready for
the next one, without wasting CPU.
However, if the user set their texture load speed to "Instant", that
means they never want to see any original textures. So in that case, we
do still wait.
Fixes#20519
* Rename LogType to Log
* Explicitly use the Log:: enum when logging. Allows for autocomplete when editing.
* Mac/ARM64 buildfix
* Do the same with the hle result log macros
* Rename the log names to mixed case while at it.
* iOS buildfix
* Qt buildfix attempt, ARM32 buildfix
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.