_Call_once, _Tss_create, _Tss_delete, _Tss_get, _Tss_set, _Thrd_equal,
_Thrd_current and _Thrd_exit call scePthreadOnce, scePthreadKeyCreate,
scePthreadKeyDelete, scePthreadGetspecific, scePthreadSetspecific,
scePthreadEqual, scePthreadSelf and scePthreadExit and return their
results unchanged, as the console's libSceLibcInternal does.
_Mtx_current_owns returns 1 there. libkernel registers the calls with
libc at load, next to the pthread_create registration.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RbLgECLQ2bpDM7oe2urGZK
Animal Well (PPSA22520) imports _Thrd_detach (L7f7zYwBvZA) from libc.prx and nothing exports it, so the Windows loader stops at startup. Register libkernel's pthread_detach with libc like pthread_create and pthread_join, and return _Thrd_error (4) when it fails.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GtXavMkgCTCdmRpweviHcQ
_pthread_cond_timedwait fails an abstime with a negative tv_sec with EINVAL
before it looks at the condition variable or the mutex. pthread_cond_timedwait
took it as a deadline in the past and answered ETIMEDOUT.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
_pthread_barrier_init fails a count above INT_MAX with EINVAL.
pthread_barrier_init accepted any count above zero.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
scePthreadAttrGet copied the attributes of any non-null handle, so a
thread that was joined or had finished still answered 0, and a thread
that ended detached was read after its object had been freed. FreeBSD
11.4's _pthread_attr_get_np returns ESRCH for a dead or reclaimed thread,
and Monster Hunter Wilds (PPSA24191) reuses a slot of its thread table
only when scePthreadAttrGet returns 0x80020003.
After the EINVAL checks it now returns ESRCH unless the handle is a live
guest thread, and copies the fields while holding the thread registry
lock (LockLiveGuestThread), so a detached thread exiting during the call
is not freed under the copy. GuestThreadIsLive uses the same lookup.
pthread_attr_get_np, which the title does not import, is left as it is;
the debt entry records the difference.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PPSA34015 (EA SPORTS FC 27) stopped with "Joining guest thread: Access is
denied": scePthreadJoin waited on a thread that another call released
under it, and then waited on its closed handle. As FreeBSD 11.4's
thr_join.c and thr_detach.c do with the joiner field, scePthreadDetach
now returns EINVAL while a thread waits to join the target, a second
concurrent scePthreadJoin returns EOPNOTSUPP, a cancelled join backs out,
and a completed join leaves the thread detached.
Locking, trylocking, unlocking a destroyed mutex and signalling, broadcasting,
waiting on or destroying a destroyed condition variable threw a C++ exception
into the guest. FreeBSD 11.4 libthr returns EINVAL for all of them (thr_mutex.c
check_and_init_mutex and mutex_unlock_common compare against THR_MUTEX_DESTROYED,
thr_cond.c CHECK_AND_INIT_COND and _pthread_cond_destroy against
THR_COND_DESTROYED). The condition wait path already reported EINVAL for a
destroyed mutex.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
libkernel exported scePthreadAttrSetschedpolicy and
scePthreadAttrSetinheritsched but not the matching getters,
scePthreadAttrGetschedpolicy (NID NMyIQ9WgWbU) and
scePthreadAttrGetinheritsched (NID lpMP8HhkBbg), so a title that
imports either one stopped at startup on the unresolved import. Dragon
Ball Xenoverse 2 (PPSA08587) imports both.
Implement them as FreeBSD 11.4 libthr implements
pthread_attr_getschedpolicy and pthread_attr_getinheritsched
(lib/libthr/thread/thr_attr.c): a null or uninitialized attribute
returns EINVAL (0x80020016), as does a null output of
scePthreadAttrGetschedpolicy; otherwise the attribute's policy or
inheritance is stored and 0 is returned. libthr writes through a null
output of the inheritance getter unchecked, so that case throws, as
pthread_attr_getinheritsched and scePthreadAttrGetsolosched do.
Neither getter was measured on a console. The scePthreadAttr entry in
docs/dev/debt/libkernel.md, which describes the calls measured on a
PS5, now says so and records the throw.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An adopted thread (the main thread, or a host thread that calls
scePthreadSelf) reported its whole Windows stack reservation, and so
did sceKernelIsStack on a host thread before adoption. A relinked
executable reserves 0x210000 bytes for its main thread and commits the
top 0x200000, so the lowest 64 KiB of the reported stack hold only
reserved pages and Windows' guard pages. mprotect fails there, so
HotSpot in Java 25 LAN / DNS (PPSA99869) could not create the main
thread's stack guard pages ("Attempt to allocate stack guard pages
failed").
When everything above the bottom allocation granule is committed
read-write, the host stack is now reported from there, as created
guest threads report only their committed stack. Other host stacks
keep the whole range. The committed-pages walk is shared with
StartNativeThread and throws when VirtualQuery fails.
scePthreadJoin checked whether the thread was detached before whether it
was the calling thread. So a detached thread joining itself got EINVAL
instead of EDEADLK, and so did the main thread, which scePthreadSelf
adopts as detached. FreeBSD's join checks the calling thread right after
the null check and before it looks at the detach state. The self check
now comes first; the null, detached and already-joined answers are
unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On a PS5 (firmware 12.70), of the values 0, 1, 2 and -1,
pthread_condattr_setpshared accepts only 0 and leaves the attribute
unchanged otherwise. pthread_condattr_getpshared reports 0 and returns
EINVAL for a null, uninitialized or destroyed attribute, also with a
null output. With an initialized attribute a null output crashes the
console; here it throws.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Measured on a PS5 (firmware 12.70): the getter reports 0, and of the
values 0, 1, 2 and -1 the setter accepts only 0 and checks the value
before the attribute. A null or uninitialized attribute, or a null
output, crashes the console; here it throws.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On a PS5 (firmware 12.70), of the values 0, 1, 2 and -1,
pthread_spin_init, pthread_barrierattr_setpshared and
pthread_mutexattr_setpshared accept only PTHREAD_PROCESS_PRIVATE (0);
1, 2 and -1 return EINVAL and leave the attribute unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scePthreadCondInit, and pthread_cond_init through it, threw when attr
pointed to a null attribute: a zeroed one that was never initialized or
one that scePthreadCondattrDestroy has set to null. FreeBSD 11.4 libthr
(thr_cond.c, cond_init) takes a null attribute as the default one and
creates a CLOCK_REALTIME condition variable. A PS5 (firmware 13.60)
takes a zeroed attribute as the default one in scePthreadMutexInit
(#4158). Take it as the default here too, as scePthreadMutexInit and
scePthreadCreate already do.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PSFlyCast (PPSA99247) imports pthread_condattr_setpshared (3BpP850hBT4)
from libkernel and fails to load without it:
"./app.elf: symbol lookup error: ./app.elf: undefined symbol: 3BpP850hBT4".
The attribute stores PTHREAD_PROCESS_PRIVATE (0) or
PTHREAD_PROCESS_SHARED (1); a null or uninitialized attribute and any
other value return EINVAL without changing it, following FreeBSD 11
libthr thr_condattr.c and pthread_mutexattr_setpshared here. Sharing
across processes is not modeled, as for mutexes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sovthwyu4H63RMbRVha2Sy