core: lock-free run-gate (atomic frames_to_run) e60badb602fb
retro_control_running() is called every instruction; read the run budget as a relaxed atomic instead of taking the mutex. The mutex still guards the /step completion handshake (on_frame/do_step). Git-Commit: d851e270f69dd9fb52b29c8742b3a92e4e731bde Git-Author: Andy McCall <[email protected]>
- Author
- Andy McCall @andymccall <[email protected]>
- When
- · 2026-07-19 22:30 UTC
- Signature
- ◈ sealed by Andy McCall
- Hash
e60badb602fbbcd6e49e1813cf72fd10079d85b79ec43f4ca50d2c075d750f58- Depends on
- 961b3c610c66
- Depended on by
- nothing yet
- In bookmarks
- main perf-6
- Edits
- 4 atoms, 0 tree operations, 1 file
Browse the tree at this change
modified core/retro_control.c +9 −6
| … | 20 unchanged lines |
||
| 21 | 21 | #else |
|
| 22 | 22 | ||
| 23 | 23 | #include <pthread.h> |
|
| 24 | + | #include <stdatomic.h> |
|
| 24 | 25 | #include <unistd.h> |
|
| 25 | 26 | #include <errno.h> |
|
| 26 | 27 | #include <signal.h> |
|
| … | 14 unchanged lines |
||
| 41 | 42 | static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER; |
|
| 42 | 43 | static pthread_cond_t g_cv = PTHREAD_COND_INITIALIZER; |
|
| 43 | 44 | ||
| 44 | - | /* run control: -1 free-run, 0 halted, >0 run this many frames then halt */ |
|
| 45 | - | static long g_frames_to_run = -1; |
|
| 45 | + | /* run control: -1 free-run, 0 halted, >0 run this many frames then halt. |
|
| 46 | + | * Atomic so retro_control_running() (called every instruction) reads it without |
|
| 47 | + | * taking the lock — the mutex is kept only for the /step completion handshake. */ |
|
| 48 | + | static _Atomic long g_frames_to_run = -1; |
|
| 46 | 49 | static int g_step_waiting = 0; |
|
| 47 | 50 | ||
| 48 | 51 | /* single-slot marshalled request (mem / regs / screenshot) */ |
|
| … | 82 unchanged lines |
||
| 131 | 134 | int retro_control_running(void) |
|
| 132 | 135 | { |
|
| 133 | 136 | if (!g_be) return 1; |
|
| 134 | - | pthread_mutex_lock(&g_lock); |
|
| 135 | - | long f = g_frames_to_run; |
|
| 136 | - | pthread_mutex_unlock(&g_lock); |
|
| 137 | - | return f != 0; |
|
| 137 | + | /* Lock-free hot path: a word-sized atomic read, no mutex. The gate |
|
| 138 | + | * tolerates a one-iteration-stale value; /step correctness is enforced by |
|
| 139 | + | * the mutex + condvar in on_frame/do_step, not by this read. */ |
|
| 140 | + | return atomic_load_explicit(&g_frames_to_run, memory_order_relaxed) != 0; |
|
| 138 | 141 | } |
|
| 139 | 142 | ||
| 140 | 143 | void retro_control_on_frame(void) |
|
| … | 222 unchanged lines |