Skip to content

feat(libkernel): add mutex ownership, relative lock and spin/yield accessors - #8400

Merged
adriadam10 merged 2 commits into
boykopovar:mainfrom
slider:feat/libkernel-mutex-np
Oct 21, 2026
Merged

adriadam10 merged 2 commits into
boykopovar:mainfrom
slider:feat/libkernel-mutex-np

Conversation

@slider

@slider slider commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

What

Adds 10 missing libkernel mutex extensions, following FreeBSD 11.4 libthr (thr_mutex.c):

  • pthread_mutex_isowned_np: 1 when the calling thread owns the mutex, otherwise 0. A static initializer or destroyed mutex reports 0 without being initialized, as _pthread_mutex_isowned_np does.
  • pthread_mutex_reltimedlock_np: the POSIX name of the existing relative scePthreadMutexTimedlock, with the same static-initializer handling as the other POSIX lock calls.
  • pthread_mutex_getspinloops_np, pthread_mutex_setspinloops_np, pthread_mutex_getyieldloops_np and pthread_mutex_setyieldloops_np, plus scePthreadMutexGetspinloops, Setspinloops, Getyieldloops and Setyieldloops. They follow check_and_init_mutex: a static initializer is initialized and a destroyed mutex returns EINVAL. The exception is setting the yield count, which returns 0 as FreeBSD's __pthread_mutex_setyieldloops_np does.
  • New mutexes take FreeBSD's mutex_init_body defaults: 2000 spins for an adaptive mutex and 0 otherwise. PthreadMutexPrivate::SetType sets them at the three places a mutex is created.
  • Debt (docs/dev/debt/libkernel.md): the counts are stored and reported but host mutexes do not spin or yield by them, and the console's defaults are unverified.

Left out on purpose:

  • pthread_mutex_getprioceiling and setprioceiling (and their SCE names): mutexes here do not carry the priority protocol, and FreeBSD's setter locks the mutex through UMTX_OP_SET_CEILING.
  • scePthreadMutexIsowned: shadPS4 wraps it with the error-converting ORBIS() wrapper, which would turn "owned" into 0x80020001. Its console behaviour is undocumented.

No overlap with #8373: the branches merge cleanly (git merge-tree).

Tested

Linux (Ubuntu 24.04, GCC 13.3, Release):

  • New cases in guest_pthread_mutex_errors pass: ownership from the owner and another thread, reltimedlock_np deadlock and timeout, destroyed and static-initializer mutexes, and spin/yield defaults per type, round trips and errors.
  • guest_pthread_mutexattr, guest_cond_timedwait, guest_cond_recursive_mutex, guest_pthread_destroyed_objects and guest_kernel_errors pass.
  • Breaking the adaptive default or the ownership check makes the new tests fail.
  • tools/check_conventions.py --base origin/main passes.

Windows: the changed sources and test pass a syntax-only check with MinGW-w64 GCC 13 (not the supported 15.2); not built or run.

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
  • GPUs tested: n/a
  • AI-assisted: yes

@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Progress report (f894ba6 → 31fc06b)

📈 System libraries: 50.64% (+0.06%, +10 implemented functions)

✅ 10 implemented
Library Name
libkernel pthread_mutex_getspinloops_np_nid_postfix
libkernel pthread_mutex_getyieldloops_np_nid_postfix
libkernel pthread_mutex_isowned_np_nid_postfix
libkernel pthread_mutex_reltimedlock_np_nid_postfix
libkernel pthread_mutex_setspinloops_np_nid_postfix
libkernel pthread_mutex_setyieldloops_np_nid_postfix
libkernel scePthreadMutexGetspinloops
libkernel scePthreadMutexGetyieldloops
libkernel scePthreadMutexSetspinloops
libkernel scePthreadMutexSetyieldloops

@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
PR 8087 core/libs/prx/libkernel/Pthread/src/Mutex.cpp L155-156

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 4630 docs/dev/debt/libkernel.md
PR 5021 core/libs/prx/libkernel/Pthread/include/Pthread.hpp
docs/dev/debt/libkernel.md
PR 6044 core/libs/tests/GuestPthreadMutexErrors.cpp
PR 6149 docs/dev/debt/libkernel.md
PR 6469 docs/dev/debt/libkernel.md
PR 6586 docs/dev/debt/libkernel.md
PR 6740 core/libs/prx/libkernel/Pthread/include/Pthread.hpp
docs/dev/debt/libkernel.md
PR 6879 docs/dev/debt/libkernel.md
PR 6936 docs/dev/debt/libkernel.md
PR 6977 docs/dev/debt/libkernel.md
PR 7049 docs/dev/debt/libkernel.md
PR 7088 docs/dev/debt/libkernel.md
PR 7105 docs/dev/debt/libkernel.md
PR 7121 docs/dev/debt/libkernel.md
PR 7149 core/libs/prx/libkernel/Pthread/include/Pthread.hpp
docs/dev/debt/libkernel.md
PR 7192 docs/dev/debt/libkernel.md
PR 7447 docs/dev/debt/libkernel.md
PR 7509 docs/dev/debt/libkernel.md
PR 8520 docs/dev/debt/libkernel.md
PR 8592 core/libs/prx/libkernel/Pthread/include/Pthread.hpp
PR 8726 docs/dev/debt/libkernel.md

@nikowolf123

Copy link
Copy Markdown
Contributor

core/libs/prx/libkernel/Pthread/Posix/Mutex.cpp L82: pthread_mutex_reltimedlock_np takes (PthreadMutex*, KernelUseconds), where the count is 32 bits (SceTypes.hpp L38). The description cites no source for this signature, and the debt file does not record it. FreeBSD 11.4 has no such function: it is not in thr_mutex.c, pthread_np.h or pthread.map. The only implementation I found that gives a signature is shadPS4. It reads a 64-bit count and registers that one function for this NID (nbQ0bXMRlhk) and for scePthreadMutexTimedlock. If the console also reads 64 bits, take pthread_mutex_reltimedlock_np(&m, 0x100000000) (about 71.6 minutes) on a mutex another thread holds. Here only the low 32 bits are read, which are 0, so the call returns ETIMEDOUT at once instead of waiting.

CONTRIBUTING.md L73 asks for signatures to be recorded in technical debt. The pthread_cond_reltimedwait_np entry already does this for the same case. A matching line next to it would cover this one:

- [pthread_mutex_reltimedlock_np](../../../core/libs/prx/libkernel/Pthread/Posix/Mutex.cpp) (libkernel) takes `(mutex, usec)`, a relative timeout in microseconds, and is `scePthreadMutexTimedlock` with POSIX error numbers. FreeBSD 11.4 has no such function; the signature comes only from shadPS4, which registers one function for this NID and for `scePthreadMutexTimedlock` ([`mutex.cpp`](https://github.com/shadps4-emu/shadPS4/blob/3a9f57265d28975658f1ca941daa5c879c7a74bd/src/core/libraries/kernel/threads/mutex.cpp#L284-L287)). shadPS4 reads a 64-bit count; here it is the 32-bit `SceKernelUseconds` of the SCE twin, as for `pthread_cond_reltimedwait_np`. Unverified on the console

@oneandonlydean

Copy link
Copy Markdown
Collaborator

@slider The code looks right to me: the spin defaults reach every creation path (the no-attr pthread_mutex_init case ends up non-adaptive, so 0 spins is correct), the ownership check handles static and destroyed mutexes without initialising them, and everything compiles with the Windows toolchain too.

One thing before it can go in, the same point nikowolf123 made: pthread_mutex_reltimedlock_np takes (mutex, KernelUseconds), but no source gives that signature (FreeBSD 11.4 has no such function, and shadPS4 reads a 64-bit count). Please record it in docs/dev/debt/libkernel.md next to the pthread_cond_reltimedwait_np entry; nikowolf123's suggested line works. If you have a source showing the console reads 64 bits, switch the parameter to std::uint64_t instead.

After that, the bar is a full CI run with guest_pthread_mutex_errors passing on Linux and Windows. Note that #8087 also edits Pthread/src/Mutex.cpp, so whichever lands second needs a rebase.

@slider
slider force-pushed the feat/libkernel-mutex-np branch from 6127294 to 31fc06b Compare October 21, 2026 08:02
@adriadam10 adriadam10 self-assigned this Oct 21, 2026
@slider

slider commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @nikowolf123 and @oneandonlydean. Added the debt entry next to pthread_cond_reltimedwait_np (separate commit, 5993f57… after rebase: docs(debt): record the pthread_mutex_reltimedlock_np timeout width). I found no source that the console reads 64 bits: FreeBSD 11.4 has no such function, the ps5-payload-dev SDK headers don't declare it, and only shadPS4 (u64 usec, mutex.cpp L284-L287 at 7c960ea) gives a signature. So the parameter stays the 32-bit SceKernelUseconds of the scePthreadMutexTimedlock twin, as for pthread_cond_reltimedwait_np.

Also rebased onto current main; guest_pthread_mutex_errors and the related mutex/cond tests pass on Linux, and the changed files pass a MinGW syntax check. Could a collaborator start the full CI run (Linux and Windows)? If #8087 lands first I'll rebase again.

@adriadam10
adriadam10 merged commit 1ae3f38 into boykopovar:main Oct 21, 2026
10 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the FreeBSD 11.4 thr_mutex.c defaults and the static/destroyed-mutex handling, that the new guest_pthread_mutex_errors cases pin values only this change produces, and that the reltimedlock_np timeout width is now recorded in docs/dev/debt/libkernel.md as requested; merged.

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