diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp index 2b2dd46e..c7072019 100644 --- a/app/src/main/cpp/skyline/kernel/svc.cpp +++ b/app/src/main/cpp/skyline/kernel/svc.cpp @@ -185,6 +185,7 @@ namespace skyline::kernel::svc { std::vector waitHandles(numHandles); state.thisProcess->ReadMemory(waitHandles.data(), state.nce->GetRegister(Xreg::X1), numHandles * sizeof(handle_t)); std::string handleStr; + uint index{}; for (const auto &handle : waitHandles) { handleStr += fmt::format("* 0x{:X}\n", handle); auto object = state.thisProcess->handleTable.at(handle); @@ -194,19 +195,22 @@ namespace skyline::kernel::svc { case type::KType::KEvent: case type::KType::KSession: break; - default: + default: { state.nce->SetRegister(Wreg::W0, constant::status::InvHandle); + state.thisThread->ClearWaitObjects(); return; + } } auto syncObject = std::static_pointer_cast(object); if (syncObject->signalled) { state.logger->Debug("Found signalled handle: 0x{:X}", handle); state.nce->SetRegister(Wreg::W0, constant::status::Success); - state.nce->SetRegister(Wreg::W1, handle); + state.nce->SetRegister(Wreg::W1, index); + state.thisThread->ClearWaitObjects(); return; } state.thisThread->waitObjects.push_back(syncObject); - syncObject->waitThreads.emplace_back(state.thisThread->pid, handle); + syncObject->waitThreads.emplace_back(state.thisThread->pid, index); } state.logger->Debug("Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, state.nce->GetRegister(Xreg::X3)); if (state.nce->GetRegister(Xreg::X3) != std::numeric_limits::max()) diff --git a/app/src/main/cpp/skyline/kernel/types/KSyncObject.cpp b/app/src/main/cpp/skyline/kernel/types/KSyncObject.cpp index d1aa73d5..6115a627 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSyncObject.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KSyncObject.cpp @@ -4,12 +4,13 @@ namespace skyline::kernel::type { KSyncObject::KSyncObject(const skyline::DeviceState &state, skyline::kernel::type::KType type) : KObject(state, type) {} - KSyncObject::threadInfo::threadInfo(pid_t process, handle_t handle) : process(process), handle(handle) {} + KSyncObject::threadInfo::threadInfo(pid_t process, u32 index) : process(process), index(index) {} void KSyncObject::Signal() { for (const auto &info : waitThreads) { - state.nce->SetRegister(Wreg::W1, info.handle); + state.nce->SetRegister(Wreg::W1, info.index); state.os->processMap.at(info.process)->threadMap.at(info.process)->status = KThread::Status::Runnable; } + waitThreads.clear(); } } diff --git a/app/src/main/cpp/skyline/kernel/types/KSyncObject.h b/app/src/main/cpp/skyline/kernel/types/KSyncObject.h index 741add4f..c35c5472 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSyncObject.h +++ b/app/src/main/cpp/skyline/kernel/types/KSyncObject.h @@ -15,9 +15,9 @@ namespace skyline::kernel::type { */ struct threadInfo { pid_t process; //!< The PID of the waiting thread - handle_t handle; //!< The handle in the process's handle table + u32 index; //!< The index of the object in the wait list - threadInfo(pid_t process, handle_t handle); + threadInfo(pid_t process, u32 index); }; std::vector waitThreads; //!< A vector of threads waiting on this object diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.cpp b/app/src/main/cpp/skyline/kernel/types/KThread.cpp index 4bbd9d93..eae18eec 100644 --- a/app/src/main/cpp/skyline/kernel/types/KThread.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KThread.cpp @@ -37,4 +37,18 @@ namespace skyline::kernel::type { if (status == Status::Sleeping) status = Status::Runnable; } + + void KThread::ClearWaitObjects() { + for (auto &object : waitObjects) { + auto iter = object->waitThreads.begin(); + while (iter != object->waitThreads.end()) { + if (iter->process == pid) { + object->waitThreads.erase(iter); + break; + } + iter++; + } + } + waitObjects.clear(); + } } diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.h b/app/src/main/cpp/skyline/kernel/types/KThread.h index 1a462838..39227e5b 100644 --- a/app/src/main/cpp/skyline/kernel/types/KThread.h +++ b/app/src/main/cpp/skyline/kernel/types/KThread.h @@ -22,7 +22,7 @@ namespace skyline::kernel::type { WaitCondVar, //!< The thread is waiting on a Conditional Variable Runnable //!< The thread is ready to run after waiting } status = Status::Created; //!< The state of the thread - std::vector> waitObjects; //!< A vector holding handles this thread is waiting for + std::vector> waitObjects; //!< A vector holding the objects this thread is waiting for u64 timeout{}; //!< The end of a timeout for svcWaitSynchronization or the end of the sleep period for svcSleepThread handle_t handle; // The handle of the object in the handle table pid_t pid; //!< The PID of the current thread (As in kernel PID and not PGID [In short, Linux implements threads as processes that share a lot of stuff at the kernel level]) @@ -63,6 +63,11 @@ namespace skyline::kernel::type { */ void WakeUp(); + /** + * @brief This clears all the objects in the waitObjects vector + */ + void ClearWaitObjects(); + /** * @brief Update the priority level for the process. * @details Set the priority of the current thread to `priority` using setpriority [https://linux.die.net/man/3/setpriority]. We rescale the priority from Nintendo scale to that of Android. diff --git a/app/src/main/cpp/skyline/nce.cpp b/app/src/main/cpp/skyline/nce.cpp index 44b3e8ec..0d5d3069 100644 --- a/app/src/main/cpp/skyline/nce.cpp +++ b/app/src/main/cpp/skyline/nce.cpp @@ -78,7 +78,7 @@ namespace skyline { } } if (state.thisThread->status == kernel::type::KThread::Status::Runnable) { - state.thisThread->waitObjects.clear(); + state.thisThread->ClearWaitObjects(); state.thisThread->status = kernel::type::KThread::Status::Running; currRegs.pc += sizeof(u32); WriteRegisters(currRegs);