// Copyright 2018 plutoo #include "result.h" #include "kernel/svc.h" #include "kernel/wait.h" #include "kernel/waiter.h" #include "kernel/utimer.h" #include "kernel/uevent.h" #include "arm/counter.h" #include "waiter.h" #include "utimer.h" #include "uevent.h" #include "../internal.h" Result waitN(s32* idx_out, WaitObject* objects, size_t num_objects, u64 timeout) { if (num_objects > MAX_WAIT) return MAKERESULT(Module_Libnx, LibnxError_TooManyWaitables); Handle dummy_handle = getThreadVars()->handle; Waiter waiter; _waiterCreate(&waiter); Handle handles[MAX_WAIT]; u64 cur_tick = armGetSystemTick(); u64 end_time = timeout; s32 end_time_idx = -1; size_t i; for (i=0; itype) { case WaitObjectType_UsermodeTimer: timer_tick = _utimerGetNextTime(obj->timer); // Skip timer if disabled. if (timer_tick == 0) break; // If the timer already signalled, we're done. if (timer_tick < cur_tick) { *idx_out = i; _utimerRecalculate(obj->timer, timer_tick); _waiterFree(&waiter, objects); return 0; } // Override the user-supplied timeout if timer would fire before that. if ((timer_tick - cur_tick) < end_time) { end_time = timer_tick - cur_tick; end_time_idx = i; } break; case WaitObjectType_UsermodeEvent: // If the event already happened, we're done. if (_ueventConsumeIfSignalled(obj->event)) { *idx_out = i; _waiterFree(&waiter, objects); return 0; } // If not, add a listener. _waiterSubscribe(&waiter, obj->event); break; case WaitObjectType_Handle: break; } handles[i] = (obj->type == WaitObjectType_Handle) ? obj->handle : dummy_handle; } // Do the actual syscall. Result rc; rc = svcWaitSynchronization(idx_out, handles, num_objects, end_time); // Timeout-error? if (rc == 0xEA01) { // If the user-supplied timeout, we return the error back to them. if (end_time_idx == -1) { _waiterFree(&waiter, objects); return rc; } // If not, it means a timer was triggered. *idx_out = end_time_idx; _utimerRecalculate(objects[end_time_idx].timer, end_time + cur_tick); _waiterFree(&waiter, objects); return 0; } // Interrupted-error? if (rc == 0xEC01) { // An event was signalled. *idx_out = _waiterGetSignalledIndex(&waiter); _waiterFree(&waiter, objects); return 0; } _waiterFree(&waiter, objects); return rc; }