Skip to content

feat(libc): implement _Mtx_timedlock - #10688

Merged
oneandonlydean merged 2 commits into
boykopovar:mainfrom
edubox:feat/libc-mtx-timedlock
Oct 25, 2026
Merged

oneandonlydean merged 2 commits into
boykopovar:mainfrom
edubox:feat/libc-mtx-timedlock

Conversation

@edubox

@edubox edubox commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

What

Export _Mtx_timedlock (hPzYSd5Nasc), the timed counterpart of _Mtx_lock, which Minecraft Legends (PPSA05510) imports from libc.prx.

It takes the same absolute xtime as _Cnd_timedwait, converts it once through the shared XtimePoint helper, and keeps the mutex's recursive bookkeeping: a non-recursive mutex already held by the caller returns _Thrd_busy (3), a recursive one raises the count, and a free mutex acquires immediately. Expiry returns _Thrd_timedout (2); other host failures return 5, matching the console's libc.prx at 0x5d50 (PPSA02530), where 0x8002003c becomes 2 and every other nonzero result becomes 5.

On non-Windows hosts the native mutex and condition are std::timed_mutex and std::condition_variable_any. Windows keeps the previous CRITICAL_SECTION/CONDITION_VARIABLE pair and its WaitUntil loop because the standard condition_variable_any path failed guest_libc_cnd_timed_wait on the full Windows runner; _Mtx_timedlock polls TryEnterCriticalSection with Sleep(1) until the deadline. docs/dev/debt/libc.md records that the Windows timing of both the standard primitives and this polling path is not measured on the console.

pr_overlap finds no shared export. It shares docs/dev/debt/libc.md:38 with #8903, and the PRs that conflict with the base also touch Threads.cpp/GuestLibcThreads.cpp (#1835, #5021, #7201, #9447, #10615, #10648); their diffs do not implement _Mtx_timedlock or change the native mutex type.

Tested

CachyOS Linux 7.3.0-3, Ryzen 9 9900X, GCC 16.2.1, main 137a8fab89 plus this PR.

  • guest_libc_threads passes with TimedMutex: acquire with a future deadline, same-thread non-recursive busy, another thread times out (2) while the mutex is held, release, null handle and null deadline throws, and a recursive mutex takes the timed lock twice.
  • guest_libc_cnd_timed_wait passes with the restored Windows path (Linux host).
  • The patched libc.prx exports hPzYSd5Nasc (nm -D).
  • Not tested with a title. This removes one of the libc imports PPSA05510 needs; the title still stops on the next one.
  • The previous head failed guest_libc_cnd_timed_wait on the Windows full CI; this head restores the path that passed there. A Windows rerun is pending (no MinGW locally).

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none (removes one of the libc imports PPSA05510 needs; it still stops on the next one)
  • GPUs tested: n/a
  • AI-assisted: yes

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Progress report (75227c7 → 11bc03f)

➖ System libraries: 49.35% (+0.0%, +1 implemented functions)

✅ 1 implemented
Library Name
libc _Mtx_timedlock_nid_postfix

Changed libraries (implemented exports)

Library Before After Change
libc 1340/1351 (99.19%) 1341/1352 (99.19%) +0.00 pp

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact head e46fd5038350e4a0e4d5e7112af00e14f480736a. The shared XtimePoint conversion keeps the existing overflow/normalization checks while giving both timed condition waits and timed mutex acquisition the same absolute deadline. The timed path checks ownership before locking, preserves recursive-count handling, and maps timeout and system errors to the stated thread results. The Linux guest_libc_threads and guest_libc_cnd_timed_wait runs are reported passing by the author; locally, both changed translation units passed MinGW syntax checks (with a define for a high-resolution timer constant missing from this container's older MinGW headers). git diff --check and merge-tree checks pass. Hosted product tests are skipped, and no Windows runtime test is reported, so Windows behavior remains unverified here; I found no blocking source issue in the reviewed code.

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the full diff at e46fd50. The new export uses the shared absolute-xtime conversion, preserves recursive ownership bookkeeping, returns busy for a same-thread plain mutex and timedout on expiry; the Windows native mutex/condition pair is unified with the timed-capable standard primitives so _Cnd_wait and _Cnd_timedwait share the same mutex. The focused test covers future acquisition, same-thread busy, cross-thread timeout, invalid arguments and recursive acquisition; the author reports the libc thread tests pass on Linux. Hosted Linux/Windows/macOS relinker and ASAN jobs, register-context on Ubuntu/macOS and write-watch on macOS pass; product Linux/Windows jobs were skipped. No title execution is claimed.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 24, 2026

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation adds the missing timed-lock export, shares the absolute XTIME conversion with timed condition waits, and retains the existing recursive/non-recursive ownership bookkeeping. The Linux tests cover future acquisition, same-thread busy, another-thread timeout, recursive reacquisition, invalid handles/deadline, and the existing timed condition wait; the PR also reports inspection of the console error mapping and export NID. I verified the diff against current main, git diff --check, and conventions. Hosted relinker/ASan, register-context and write-watch matrices pass across the available platforms; product build jobs are path-skipped.

@edubox
edubox force-pushed the feat/libc-mtx-timedlock branch from e46fd50 to b3c9d35 Compare October 25, 2026 01:25
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 25, 2026
@edubox

edubox commented Oct 25, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto main f26434a (#10706). _Mtx_timedlock is now declared in core/libs/prx/libc/include/Api.hpp; the test uses the canonical Xtime and headers instead of local declarations. The std::timed_mutex/condition_variable_any implementation is unchanged. guest_libc_threads and guest_libc_cnd_timed_wait pass; conventions are clean. New head b3c9d35ae2; the macOS queue is still finishing.

@oneandonlydean oneandonlydean self-assigned this Oct 25, 2026
@oneandonlydean

Copy link
Copy Markdown
Collaborator

@edubox Full CI on b3c9d35 (merged onto current main) fails on Windows only: guest_libc_cnd_timed_wait aborts in libc.prx with exit code 0xc0000409 after 0.6 s (SIGABRT on a worker thread; run https://github.com/boykopovar/AnyPS5/actions/runs/40175154849, Windows job). The same test passes on Linux in this run and on both lanes on main. The PR switches the guest mutex/condition variable to std::timed_mutex / std::condition_variable_any on every platform and removes the Windows CRITICAL_SECTION path, so the Windows timed wait is the likely place to look. Could you check it on Windows (MinGW, Release) and push a fix?

@xXPBSXx

xXPBSXx commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Windows reproduction of the CI failure on this PR, measured on the PR head b3c9d35ae2 as it sits on main f26434afa3 (one commit, no local merge).

  • Windows 10, MinGW-w64 GCC 15.2, Release: guest_libc_cnd_timed_wait aborts in 3 of 3 runs, exit code 0xc0000409 after about 0.7 s (FATAL: abort() (SIGABRT)), the top frames of the abort stack are inside libc.prx.
  • Control on the same tree and build directory, with only Threads.cpp and Api.hpp put back to main: the test passes in 3 of 3 runs.
  • Ubuntu 24.04 under WSL2 (a virtualised kernel, not bare-metal), GCC 13.3, Release, same head: guest_libc_cnd_timed_wait and guest_libc_threads pass in 3 of 3 runs.
    This shows the abort comes with this change on Windows and not on main or Linux. I did not map the abort address to a source line (the libc.prx addresses do not resolve to symbols here), so the cause is not measured.

AI-assisted (Claude Code).

std::condition_variable_any regressed guest_libc_cnd_timed_wait on the Windows runner. Keep CRITICAL_SECTION/CONDITION_VARIABLE on Windows and poll TryEnterCriticalSection for _Mtx_timedlock.
@edubox

edubox commented Oct 25, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the Windows report. Pushed 11bc03f8f4, which restores the previous CRITICAL_SECTION/CONDITION_VARIABLE path on Windows instead of std::condition_variable_any; non-Windows still uses std::timed_mutex/condition_variable_any. _Mtx_timedlock on Windows polls TryEnterCriticalSection with Sleep(1) until the deadline, so the new export remains. The PR body and the debt entry are updated.

Linux: guest_libc_threads and guest_libc_cnd_timed_wait pass, and check_conventions is clean. I have no MinGW here, so could you rerun the Windows full CI on this head? If you still have the failing assertion from the previous run, sharing it would confirm the 1 ms timing loop was the only issue.

@xXPBSXx

xXPBSXx commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Windows rerun on the new head 11bc03f8f4, which sits on main f26434afa3 (two commits, no local merge). The head was read from the PR just before the build.

  • Windows 10, MinGW-w64 GCC 15.2, Release: the build succeeds, and guest_libc_cnd_timed_wait and guest_libc_threads pass in 3 of 3 runs.
  • For comparison, on the previous head b3c9d35ae2 the same test aborted in 3 of 3 runs (exit code 0xc0000409 after about 0.7 s). The saved log of that abort contains only FATAL: abort() (SIGABRT) and a stack; it has no assertion text, so there is no assertion to report.
    Not measured: Linux on this head, macOS, how closely the polling wait meets its deadline, and the cause of the earlier abort.

AI-assisted (Claude Code).

@oneandonlydean
oneandonlydean merged commit 74a55da into boykopovar:main Oct 25, 2026
19 checks passed
@oneandonlydean oneandonlydean mentioned this pull request Oct 25, 2026
12 tasks done
@edubox
edubox deleted the feat/libc-mtx-timedlock branch October 25, 2026 22:44
@oneandonlydean oneandonlydean mentioned this pull request Oct 26, 2026
12 tasks done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants