Files
AnyPS5/core/libs/tests/GuestPPSA01530Exports.cpp
T
DavidandClaude Fable 5.1 9ef4aa2c40 feat(libkernel): implement kqueue and kevent over the event queue
Cloudberry Kingdom (PPSA23827, #3177) calls kqueue right after start-up
and stopped on the throwing declarations merged with #3337; Palworld's
Discord module (PPSA23126, #2648) imports kevent.

kqueue reserves a host null-device descriptor in the file descriptor
space and registers it as an event queue that reports each ready event
once per call and moves level-triggered ones behind the others, as
kqueue_scan does. close and sceKernelClose close the queue and drop the
descriptor's events from every queue, dup2 drops them for the target,
and dup/dup2 of a kqueue throw, so a reused descriptor number is never
read as a stale kqueue.

kevent follows FreeBSD 11 kern_event.c (release/11.0.1 34bd3475):
kqueue_kevent for the changelist (filter 0 skipped, EV_SYSFLAGS
cleared, EV_ERROR receipts with the errno in data, EV_RECEIPT, the
early return when nevents is exhausted), kqueue_register for EV_ADD,
EV_DELETE, EV_ENABLE, EBADF, ENOENT and EINVAL, kqueue_scan for the
timeout (EINVAL for a bad timespec, zero polls, above INT32_MAX waits
forever) and filt_timerattach, filt_usertouch for the timer and user
filters. Read and write events reuse the guest socket poll of
sceKernelAddReadEvent/WriteEvent.

Throws: other filters, EV_DISABLE, EV_DISPATCH, EV_FORCEONESHOT,
NOTE_LOWAT, EV_CLEAR on a socket, read/write events on non-socket
descriptors or another kqueue, changes to an existing timer (11.0 and
11.4 differ), a NOTE_NSECONDS fraction above one second and a negative
nevents. Recorded in TechnicalDebt.

Test guest_kqueue covers creation and close, timers, a user event
triggered from another thread, read and write events on a socket pair,
EV_ERROR receipts, the timeout and the error cases.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 22:36:59 +02:00

45 lines
1.3 KiB
C++

#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstdio>
#include <stdexcept>
#include <string>
extern "C" {
int APS5_VABI sceNetShowIfconfig();
int APS5_VABI scePadUnknown_n3kSX62fgNo();
int APS5_VABI _ZN3sce4Json5Value21setNullAccessCallBackEPFRKS1_NS0_9ValueTypeEPS2_PvES6_();
}
namespace {
struct Export {
const char* name;
int (APS5_VABI *function)();
};
const Export exports[] = {
{"sceNetShowIfconfig", sceNetShowIfconfig},
{"scePadUnknown_n3kSX62fgNo", scePadUnknown_n3kSX62fgNo},
{"_ZN3sce4Json5Value21setNullAccessCallBackEPFRKS1_NS0_9ValueTypeEPS2_PvES6_", _ZN3sce4Json5Value21setNullAccessCallBackEPFRKS1_NS0_9ValueTypeEPS2_PvES6_},
};
bool ReportsNotImplemented(const Export& entry) {
try {
entry.function();
} catch (const std::runtime_error& error) {
if (std::string(error.what()) == std::string(entry.name) + " not implemented") return true;
std::fprintf(stderr, "%s threw: %s\n", entry.name, error.what());
return false;
}
std::fprintf(stderr, "%s returned instead of reporting that it is not implemented\n", entry.name);
return false;
}
}
int main() {
bool correct = true;
for (const auto& entry : exports) correct &= ReportsNotImplemented(entry);
return correct ? 0 : 1;
}