tools+docs: locate the lost resume, and a title test that is neither too narrow nor too loose

The stalled loader thread is a lost wakeup in Xenia's POSIX threading, fixed on
the canary branch as a60fe7d11 and written up here. A thread created suspended
publishes state_ and suspend_count_ in two separate lock scopes, and Resume()
waits only for state_ before testing suspend_count_ == 0 - so a resumer in the
gap drops the resume and the thread waits forever. The Linux XThread::Resume
discards that false, which is why the guest saw success.

On the first clean boot after the fix the loader thread is the CALLER on 20
kernel-call lines and issues 4 ResolvePath reads. Every failed boot before it had
exactly zero of both.

Stated plainly as not shown: that boots now reach the menu RELIABLY. One post-fix
boot, and it is confounded by the harness.

Which is the second half. skip_intro.sh's title test has now been wrong twice in
opposite directions: originally one absolute pixel (625,618) - a 1280x720
coordinate against the 1279x675 game surface, so it read the copyright line and
timed out with the title on screen - and then my replacement, screen_id.py, which
is too loose and called the SQUARE ENIX publisher logo "title" 151s into a boot,
spending the script's single press there. is_title.py now counts the green (A)
glyph over the whole frame: geometry-independent and specific, measured at 0
pixels on the logo and 1520 on a real title.
This commit is contained in:
Sylpheed RE agent
2026-08-19 10:41:43 +00:00
parent 24c1c940e6
commit ae3f37d3ec
4 changed files with 130 additions and 10 deletions

View File

@@ -161,9 +161,21 @@ See [`structures/ui-composable-bundles.md`](structures/ui-composable-bundles.md)
**`00:00:00` host CPU time** while the process runs at 546 %. A spinning thread
burns CPU; this one never ran. A lost resume is a race, which is the first
explanation that fits the ~1-in-3 success rate.
**Next probe:** Xenia's `XThread` create/resume pair — can a resume land before
the host thread starts waiting? And capture one *successful* boot with kernel
logging, to say whether the guest sequence differs at all.
**LOCATED AND FIXED** (canary `a60fe7d11`): `threading_posix.cc` publishes a
suspended thread's `state_` and its `suspend_count_` in **two separate lock
scopes**, and `Resume()` waits only for `state_` before testing
`if (suspend_count_ == 0) return false`. A resumer in that gap drops the
resume; the thread then waits on the count forever. The Linux `XThread::Resume`
discards the `false`, so the guest saw success. Fixed by publishing both under
one lock and waiting without releasing it. On the first clean boot after, the
loader thread is the **caller** on 20 kernel-call lines with 4 `ResolvePath`
reads — every failure before had **zero** of both.
🟡 **Still to show:** that boots now reach the menu *reliably*. The post-fix
boot is confounded — `skip_intro.sh`'s title test has been wrong twice (an
absolute pixel against the wrong surface size, then `screen_id.py` matching the
SQUARE ENIX logo). Now `tools/re-capture/is_title.py` counts the green Ⓐ glyph:
0 px on the logo, 1520 on a real title. A before/after reliability count over
several boots is the remaining work.
See [`canary-scripted-input-traps.md`](canary-scripted-input-traps.md).
***Blend mode.** Everything is straight alpha-over. The near-white flash
quads (`0xf0ffffff`) and coloured ones (`0x60ff0000`) may be additive. The