mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 08:33:12 -05:00
pthread_once and scePthreadOnce marked the control as running, called the initializer and marked the control done only after it returned. A thread that left the initializer through pthread_exit or a cancellation point never came back, so the control stayed in progress and every later call on it waited forever. FreeBSD libthr runs the initializer under a cleanup handler (lib/libthr/thread/thr_once.c, _pthread_once: "THR_CLEANUP_PUSH(curthread, once_cancel_handler, once_control); init_routine(); THR_CLEANUP_POP(curthread, 0);"). once_cancel_handler stores ONCE_NEVER_DONE and wakes the waiters, and thread exit and cancellation run the cleanup handlers. POSIX requires this for cancellation: "if init_routine is a cancellation point and is canceled, the effect on once_control shall be as if pthread_once() was never called." Both functions now push such a handler around the initializer, so the control returns to its initial state and the next caller, or one already waiting, runs the initializer. scePthreadOnce waiters now retry when the control goes back to its initial state, and an exception from its initializer resets the control as it already did for pthread_once. CleanupHandler moves to Cancel.hpp so that Once.cpp can use it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>