libkernel: implement sceKernelAioWaitRequests (#1109)

kernel: implement batch AIO completion waits

Co-authored-by: nmzik <Nmzik@mail.ru>
This commit is contained in:
Henrique Reis Neves
2026-10-06 21:13:06 -03:00
committed by GitHub
parent 7415febd93
commit e7cfe5a2f7
2 changed files with 84 additions and 31 deletions
+56 -29
View File
@@ -2831,6 +2831,8 @@ constexpr int32_t KERNEL_AIO_STATE_ABORTED = 4;
constexpr int32_t KERNEL_AIO_STATE_NOTIFIED = 0x10000;
constexpr int32_t KERNEL_AIO_MAX_QUEUE = 512;
constexpr int32_t KERNEL_AIO_MAX_REQUESTS = 128;
constexpr uint32_t KERNEL_AIO_WAIT_AND = 1;
constexpr uint32_t KERNEL_AIO_WAIT_OR = 2;
struct KernelAioResult {
int64_t return_value;
@@ -2933,26 +2935,28 @@ int KYTY_SYSV_ABI KernelAioSubmitWriteCommands(KernelAioRwRequest* req, int32_t
return OK;
}
static int32_t kernel_aio_get_state(int32_t id, bool notify) {
if (!kernel_aio_is_valid_id(id)) {
return LibKernel::KERNEL_ERROR_ESRCH;
}
auto current = g_kernel_aio_state[id].load(std::memory_order_acquire);
while (notify && (current == KERNEL_AIO_STATE_COMPLETED || current == KERNEL_AIO_STATE_ABORTED)) {
if (g_kernel_aio_state[id].compare_exchange_weak(current, current | KERNEL_AIO_STATE_NOTIFIED,
std::memory_order_acq_rel)) {
break;
}
}
return current == 0 ? LibKernel::KERNEL_ERROR_ESRCH : current;
}
int KYTY_SYSV_ABI KernelAioPollRequest(int32_t id, int32_t* state) {
PRINT_NAME();
if (state == nullptr) {
return LibKernel::KERNEL_ERROR_EFAULT;
}
if (!kernel_aio_is_valid_id(id)) {
*state = LibKernel::KERNEL_ERROR_ESRCH;
return OK;
}
auto current = g_kernel_aio_state[id].load(std::memory_order_acquire);
while (current == KERNEL_AIO_STATE_COMPLETED || current == KERNEL_AIO_STATE_ABORTED) {
if (g_kernel_aio_state[id].compare_exchange_weak(current, current | KERNEL_AIO_STATE_NOTIFIED,
std::memory_order_acq_rel)) {
break;
}
}
*state = current == 0 ? LibKernel::KERNEL_ERROR_ESRCH : current;
*state = kernel_aio_get_state(id, true);
return OK;
}
@@ -2969,31 +2973,53 @@ int KYTY_SYSV_ABI KernelAioPollRequests(int32_t* ids, int32_t num, int32_t* stat
return OK;
}
int KYTY_SYSV_ABI KernelAioWaitRequest(int32_t id, int32_t* state, uint32_t* usec) {
int KYTY_SYSV_ABI KernelAioWaitRequests(int32_t* ids, int32_t num, int32_t* states, uint32_t mode,
uint32_t* usec) {
PRINT_NAME();
if (state == nullptr) {
if (ids == nullptr || states == nullptr) {
return LibKernel::KERNEL_ERROR_EFAULT;
}
if (!kernel_aio_is_valid_id(id)) {
return KernelAioPollRequest(id, state);
if (num <= 0 || num > KERNEL_AIO_MAX_REQUESTS ||
(num != 1 && mode != KERNEL_AIO_WAIT_AND && mode != KERNEL_AIO_WAIT_OR)) {
return LibKernel::KERNEL_ERROR_EINVAL;
}
uint32_t waited = 0;
auto current = g_kernel_aio_state[id].load(std::memory_order_acquire);
while (current == KERNEL_AIO_STATE_PROCESSING) {
if (usec != nullptr && *usec != 0 && waited >= *usec) {
*state = current;
return LibKernel::KERNEL_ERROR_ETIMEDOUT;
const auto collect_states = [&](bool notify) {
int32_t finished = 0;
bool newly_complete = false;
for (int32_t i = 0; i < num; i++) {
const auto current = kernel_aio_get_state(ids[i], notify);
states[i] = current;
finished += current != KERNEL_AIO_STATE_PROCESSING;
newly_complete |= current == KERNEL_AIO_STATE_COMPLETED || current == KERNEL_AIO_STATE_ABORTED;
}
return finished == num || (mode == KERNEL_AIO_WAIT_OR && newly_complete);
};
const auto start = std::chrono::steady_clock::now();
for (;;) {
const bool complete = collect_states(false);
const auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - start).count();
const bool timed_out = usec != nullptr && elapsed >= *usec;
if (complete || timed_out) {
// A competing waiter can claim the newly completed request after the first scan.
if (collect_states(true)) {
if (usec != nullptr) {
*usec = elapsed < *usec ? *usec - static_cast<uint32_t>(elapsed) : 0;
}
return OK;
}
if (timed_out) {
return LibKernel::KERNEL_ERROR_ETIMEDOUT;
}
}
Common::Thread::SleepMicro(10);
waited += 10;
current = g_kernel_aio_state[id].load(std::memory_order_acquire);
}
}
return KernelAioPollRequest(id, state);
int KYTY_SYSV_ABI KernelAioWaitRequest(int32_t id, int32_t* state, uint32_t* usec) {
return KernelAioWaitRequests(&id, 1, state, KERNEL_AIO_WAIT_AND, usec);
}
int KYTY_SYSV_ABI KernelAioDeleteRequest(int32_t id, int32_t* ret) {
@@ -3376,6 +3402,7 @@ LIB_DEFINE(InitLibKernel_1) {
LIB_FUNC("2pOuoWoCxdk", KernelAioPollRequest);
LIB_FUNC("o7O4z3jwKzo", KernelAioPollRequests);
LIB_FUNC("KOF-oJbQVvc", KernelAioWaitRequest);
LIB_FUNC("lgK+oIWkJyA", KernelAioWaitRequests);
LIB_FUNC("XQ8C8y+de+E", KernelAioSubmitWriteCommands);
LIB_FUNC("nu4a0-arQis", KernelAioInitializeParam);
LIB_FUNC("il03nluKfMk", LibKernel::KernelRaiseException);