You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
libkernel: sceKernelWaitEqueue returns a level-triggered user event several times in one call, filling the caller's buffer #3115
An event added with sceKernelAddUserEvent has no EV_CLEAR, so it stays triggered until it is deleted. The collection loop in core/libs/prx/libkernel/Equeue/Equeue.cpp keeps re-emitting it until the caller's buffer is full: a sceKernelWaitEqueue call with num = 4 on one level event returns count 4, all the same event. kqueue examines a knote once per scan and re-queues a reported level knote behind the scan marker for the next call (kqueue_scan in sys/kern/kern_event.c; kevent(2): "Multiple events which trigger the filter do not result in multiple kevents being placed on the kqueue"), so a level event is reported at most once per call and again on the next one. A title that waits with a buffer larger than one therefore sees duplicates, and AMPR completions queued behind such an event are never delivered because every call is filled with the repeats.
Reproduce
Windows 11, WinLibs GCC 15.2.0 r7, main at the time of writing: create an equeue, add a user event with sceKernelAddUserEvent, trigger it, call sceKernelWaitEqueue(eq, ev, 4, &out, NULL): out is 4 and all four entries are the same event (FreeBSD semantics: 1).
Fix
A tested fix is on my fork: husseinkad:fix/kernel-equeue-level-event-once (two commits on main; PR #2703, closed by the intake check): the two copies of the collection loop (GetTriggeredEvents and WaitForEvents) become one CollectTriggered, which only stays on the same event when a distinct queued completion follows, which the AMPR and VideoOut events rely on. Timers, HR timers and EV_CLEAR events behave as before. The Orbis behaviour was not measured on a console; that, the remaining starvation of later events when num is smaller than the number of ready level events (FreeBSD rotates them) and AMPR/VideoOut completions being returned as separate entries are recorded in TechnicalDebt. Open PR #1091 (guest socket events) also edits Equeue.cpp and Equeue.hpp and conflicts textually; its PollEvents() call has to stay in the callers before CollectTriggered.
guest_equeue_events covers a level event reported once per call with num = 4 on the poll path and on a blocking wait (also when a helper thread triggers it about 10 ms later), an edge event reported once and again after a new trigger, and two AMPR completions of one event delivered in order; it fails without the change. A probe of eight scenarios against main's and the branch's Equeue.cpp (about 6,400 checks: N level, edge and mixed events with num below, equal to and above N, one event triggered 50 times between waits, a blocked waiter triggered later, periodic and one-shot timers, 20 AMPR completions on one ident, deleting an event and the equeue while 4 threads wait, a 4-waiter/4-trigger stress of 3 seconds) passes on the branch with no event dropped or duplicated within a call, while main fails five of the eight. Linux not run.
I carried the two commits from your fix/kernel-equeue-level-event-once branch into #3489, preserving their original authorship. I resolved the overlap with merged #1091 while retaining its socket polling path. Linux Release validation passes the equeue, socket-event, AMPR, UDP and TCP tests three consecutive times each; conventions and diff checks pass.
Update: the carried fix is now available as #3489, based on current main. The integration preserves the existing socket event handling from merged #1091 and adds once-per-wait collection for level-triggered events. Local Linux Release checks passed three consecutive runs for guest_equeue_events, guest_socket_events, guest_ampr_markers, guest_ampr_threads, guest_udp, and guest_tcp. Applicable GitHub CI has also completed successfully, including the Windows relinker; full Linux/Windows builds were skipped by the contributor policy. The PR is open and clean.
Activity
MarcZX10 commentedon Oct 11, 2026
I carried the two commits from your
fix/kernel-equeue-level-event-oncebranch into #3489, preserving their original authorship. I resolved the overlap with merged #1091 while retaining its socket polling path. Linux Release validation passes the equeue, socket-event, AMPR, UDP and TCP tests three consecutive times each; conventions and diff checks pass.MarcZX10 commentedon Oct 11, 2026
Update: the carried fix is now available as #3489, based on current main. The integration preserves the existing socket event handling from merged #1091 and adds once-per-wait collection for level-triggered events. Local Linux Release checks passed three consecutive runs for guest_equeue_events, guest_socket_events, guest_ampr_markers, guest_ampr_threads, guest_udp, and guest_tcp. Applicable GitHub CI has also completed successfully, including the Windows relinker; full Linux/Windows builds were skipped by the contributor policy. The PR is open and clean.
adriadam10 commentedon Oct 11, 2026
Fixed by #3489: a level-triggered user event is reported at most once per
sceKernelWaitEqueuecall, covered byguest_equeue_events.