mirror of
https://github.com/azahar-emu/azahar.git
synced 2026-06-07 11:13:40 -04:00
kernel: suppress async IPC wakeups during shutdown
Async IPC continuations can finish while System::Shutdown is tearing down service, kernel, and timing state. The dump showed an HTTP ReceiveData RunAsync task calling Thread::WakeAfterDelay after shutdown had begun, which reached Core::Timing::ScheduleEvent with invalid timing state and crashed. Mark KernelSystem as shutting down at the start of System::Shutdown and in the kernel destructor. Route RunAsync and RunOnThreadWorker completions through HLERequestContext::WakeAfterAsync, which skips scheduling guest-thread wakes once shutdown starts and balances the pending async counter instead. Validation: git diff --check
This commit is contained in:
parent
f2250fa485
commit
d19e6086fa
5 changed files with 26 additions and 2 deletions
|
|
@ -692,6 +692,9 @@ void System::Shutdown(bool is_deserializing) {
|
|||
|
||||
// Shutdown emulation session
|
||||
is_powered_on = false;
|
||||
if (kernel) {
|
||||
kernel->BeginShutdown();
|
||||
}
|
||||
|
||||
gpu.reset();
|
||||
if (!is_deserializing) {
|
||||
|
|
|
|||
|
|
@ -135,6 +135,15 @@ HLERequestContext::HLERequestContext(KernelSystem& kernel, std::shared_ptr<Serve
|
|||
|
||||
HLERequestContext::~HLERequestContext() = default;
|
||||
|
||||
void HLERequestContext::WakeAfterAsync(s64 sleep_for) {
|
||||
if (kernel.IsShuttingDown()) {
|
||||
kernel.ReportAsyncState(false);
|
||||
return;
|
||||
}
|
||||
|
||||
thread->WakeAfterDelay(sleep_for, true);
|
||||
}
|
||||
|
||||
std::shared_ptr<Object> HLERequestContext::GetIncomingHandle(u32 id_from_cmdbuf) const {
|
||||
ASSERT(id_from_cmdbuf < request_handles.size());
|
||||
return request_handles[id_from_cmdbuf];
|
||||
|
|
|
|||
|
|
@ -259,6 +259,8 @@ public:
|
|||
std::shared_ptr<WakeupCallback> callback);
|
||||
|
||||
private:
|
||||
void WakeAfterAsync(s64 sleep_for);
|
||||
|
||||
template <typename ResultFunctor>
|
||||
class AsyncWakeUpCallback : public WakeupCallback {
|
||||
public:
|
||||
|
|
@ -311,7 +313,7 @@ public:
|
|||
kernel, result_function,
|
||||
std::move(std::async(std::launch::async, [this, async_section] {
|
||||
s64 sleep_for = async_section(*this);
|
||||
this->thread->WakeAfterDelay(sleep_for, true);
|
||||
WakeAfterAsync(sleep_for);
|
||||
}))));
|
||||
|
||||
} else {
|
||||
|
|
@ -351,7 +353,7 @@ public:
|
|||
// We use packaged_task so we can retrieve a std::future to pass to AsyncWakeUpCallback
|
||||
auto task = std::make_shared<std::packaged_task<void()>>([this, async_section] {
|
||||
s64 sleep_for = async_section(*this);
|
||||
this->thread->WakeAfterDelay(sleep_for, true);
|
||||
WakeAfterAsync(sleep_for);
|
||||
});
|
||||
|
||||
auto future = task->get_future();
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
|
|||
|
||||
/// Shutdown the kernel
|
||||
KernelSystem::~KernelSystem() {
|
||||
BeginShutdown();
|
||||
ResetThreadIDs();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -410,6 +410,14 @@ public:
|
|||
return pending_async_operations != 0;
|
||||
}
|
||||
|
||||
void BeginShutdown() {
|
||||
shutting_down.store(true, std::memory_order_release);
|
||||
}
|
||||
|
||||
bool IsShuttingDown() const {
|
||||
return shutting_down.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
void UpdateCPUAndMemoryState(u64 title_id, MemoryMode memory_mode,
|
||||
New3dsHwCapabilities n3ds_hw_cap);
|
||||
|
||||
|
|
@ -431,6 +439,7 @@ private:
|
|||
std::atomic<u32> next_object_id{0};
|
||||
|
||||
std::atomic<int> pending_async_operations{};
|
||||
std::atomic<bool> shutting_down{false};
|
||||
|
||||
// Note: keep the member order below in order to perform correct destruction.
|
||||
// Thread manager is destructed before process list in order to Stop threads and clear thread
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue