revert(libkernel): move the destroyed condition marker to its own pull request

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
orezraeyandClaude Opus 5.5 committed 2026-10-23 08:49:24 -03:00
1 parent e2b87712dd
commit 886a2b249c
3 files changed
+2 -13

No files matched your search

+1 -3
View File
@@ -25,7 +25,7 @@ std::mutex& InitializationMutex() {
}
PthreadCond destroyedCond() {
return reinterpret_cast<PthreadCond>(std::uintptr_t{1});
return reinterpret_cast<PthreadCond>(std::uintptr_t{2});
}
PthreadMutex destroyedMutex() {
@@ -175,8 +175,6 @@ int APS5_VABI scePthreadCondDestroy(PthreadCond* cond) {
std::lock_guard lock(InitializationMutex());
if (*cond == destroyedCond())
return SCE_KERNEL_ERROR_EINVAL;
if (*cond == nullptr)
return 0;
delete *cond;
std::atomic_ref<PthreadCond>(*cond).store(destroyedCond(), std::memory_order_release);
return 0;
@@ -53,19 +53,10 @@ int main() {
PthreadCond cond = nullptr;
Require(scePthreadCondInit(&cond, nullptr, "destroyed") == SCE_OK);
Require(scePthreadCondDestroy(&cond) == SCE_OK);
Require(reinterpret_cast<std::uintptr_t>(cond) == 1);
Require(scePthreadCondSignal(&cond) == SCE_KERNEL_ERROR_EINVAL);
Require(scePthreadCondBroadcast(&cond) == SCE_KERNEL_ERROR_EINVAL);
Require(scePthreadCondWait(&cond, &mutex) == SCE_KERNEL_ERROR_EINVAL);
Require(pthread_cond_signal_nid_postfix(&cond) == POSIX_EINVAL);
Require(scePthreadCondDestroy(&cond) == SCE_KERNEL_ERROR_EINVAL);
Require(pthread_cond_destroy_nid_postfix(&cond) == POSIX_EINVAL);
PthreadCond untouched = nullptr;
Require(scePthreadCondDestroy(&untouched) == SCE_OK && untouched == nullptr);
Require(scePthreadCondSignal(&untouched) == SCE_OK && untouched != nullptr);
Require(scePthreadCondDestroy(&untouched) == SCE_OK && reinterpret_cast<std::uintptr_t>(untouched) == 1);
untouched = nullptr;
Require(scePthreadCondBroadcast(&untouched) == SCE_OK && untouched != nullptr);
Require(scePthreadCondDestroy(&untouched) == SCE_OK);
}
+1 -1
View File
@@ -61,7 +61,7 @@
- [sceKernelSyncOnAddressWait](../../../core/libs/prx/libkernel/SyncOnAddress/src/SyncOnAddress.cpp) (libkernel) - the only known caller passes a null timeout and a name string as the fourth argument; the timeout is assumed to point to microseconds like the other kernel waits, and the name is ignored
- [sceKernelSyncOnAddressWait8 / sceKernelSyncOnAddressWait16 / sceKernelSyncOnAddressWait32 / sceKernelSyncOnAddressWait64](../../../core/libs/prx/libkernel/SyncOnAddress/src/SyncOnAddress.cpp) (libkernel) - libc's `__std_atomic_wait_direct_8/16/32/64` pass a microsecond timeout or null and ignore the result; the by-value comparand, return values and the 2- and 8-byte alignment of Wait16 and Wait64 are assumed
- [scePthreadRwlockDestroy, pthread_rwlock_destroy](../../../core/libs/prx/libkernel/Pthread/src/Rwlock.cpp) (libkernel) - measured on a PS5 (firmware 13.60): destroying a rwlock returns 0 whether it is free or held for reading or writing, and leaves 1 in the handle; every call on that handle then returns `EINVAL` until it is initialized again, and a zero handle is initialized on first use by the `scePthreadRwlock` calls as by the POSIX ones. A rwlock destroyed while held is not freed, so its memory leaks. Destroying a rwlock while another thread is acquiring it is not guarded
- [scePthreadCondWait / scePthreadCondTimedwait](../../../core/libs/prx/libkernel/Pthread/src/Cond.cpp) (libkernel) - the mutex's owner is checked before waiting, as in FreeBSD libthr's [`cond_wait_common`](https://github.com/freebsd/freebsd-src/blob/main/lib/libthr/thread/thr_cond.c#L1992-L2029). Measured in a payload process on a PS5 (firmware 13.60): `EPERM` (`0x80020001`) for an unowned mutex of every type, the adaptive initializer (slot 1), an uninitialized slot and a mutex owned by another thread, `EINVAL` for the destroyed mutex (slot 2), and a recursive mutex is released completely and relocked to its depth. `scePthreadCondDestroy` stores 1, which every condition call refuses with `EINVAL`, and leaves an uninitialized slot alone. Cancellation restores the mutex and depth before cleanup and a canceled waiter forwards a wake, per POSIX; its ordering is not measured
- [scePthreadCondWait / scePthreadCondTimedwait](../../../core/libs/prx/libkernel/Pthread/src/Cond.cpp) (libkernel) - before waiting, FreeBSD libthr's [`cond_wait_common`](https://github.com/freebsd/freebsd-src/blob/main/lib/libthr/thread/thr_cond.c#L1992-L2029) checks ownership through [`_mutex_owned`](https://github.com/freebsd/freebsd-src/blob/main/lib/libthr/thread/thr_mutex.c#L1166-L1178): an unowned mutex returns `EPERM`, while its destroyed marker returns `EINVAL`. An untouched adaptive static initializer (slot value 1) therefore returns `EPERM`; the test covers this, an uninitialized slot, a mutex owned by another thread, and the destroyed marker for both timed and untimed sce and POSIX waits. A recursive mutex locked several times is released completely for the wait and relocked to the same depth afterwards, as FreeBSD libthr does (`_mutex_cv_unlock`, `_mutex_cv_lock`). These FreeBSD-derived behaviors remain unverified on console hardware. Cancellation follows the [POSIX condition wait contract](https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_cond_clockwait.html): the original mutex and recursive depth are restored before cleanup, and a canceled waiter forwards a wake to the remaining waiters. The host condition state is retained across mutex reacquisition so the guest can destroy and free its condition after notification; cancellation ordering and signal replacement are not measured on a console
- [sceKernelSetEventFlag](../../../core/libs/prx/libkernel/EventFlag/src/EventFlag.cpp) (libkernel) - multi-waiter satisfaction follows fpPS4 in-order evaluation: registered waiters are evaluated in FIFO order and each satisfied waiter's clear mode is applied immediately to the pattern before evaluating subsequent waiters; this ordering is unverified on PS5 console hardware
- [sceKernelOpenEventFlag](../../../core/libs/prx/libkernel/EventFlag/src/EventFlag.cpp) (libkernel) - returns the handle of an undeleted event flag this process created with the same name, and `SCE_KERNEL_ERROR_ENOENT` otherwise. Flags owned by other processes, such as the shell's `SceShellCoreUtilAppFocus`, do not exist here, and which attribute makes a flag openable on the console is not modelled. The error code for a missing name and the choice between flags sharing a name are unverified.
- [sceKernelAioSubmitReadCommandsMultiple / sceKernelAioSubmitWriteCommandsMultiple / sceKernelAioWaitRequests / sceKernelAioPollRequests / sceKernelAioCancelRequest / sceKernelAioCancelRequests / sceKernelAioDeleteRequests](../../../core/libs/prx/libkernel/Aio/src/Aio.cpp) (libkernel) - behaviour from shadPS4 (one id per request for the Multiple submits, cancel turns any request aborted and id 0 reports processing, wait mode 2 returns once one request completed, poll copies every state without waiting); the 128 requests or ids per batch limit is from SharpProspero, with an unknown error, so larger batches throw; wait modes other than 1 (and) and 2 (or) throw; null pointers, negative counts and invalid ids return the codes the single-request siblings use, checked before any state is written