From 370ac4f64ae3ede26c48ea17fcd3dd4363258606 Mon Sep 17 00:00:00 2001 From: ManDude <7569514+ManDude@users.noreply.github.com> Date: Mon, 10 May 2021 05:00:50 +0100 Subject: [PATCH] Change VM dying logic to prevent deadlocks (#433) --- game/system/vm/vm.cpp | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/game/system/vm/vm.cpp b/game/system/vm/vm.cpp index 5b59dd7c9f..a252534779 100644 --- a/game/system/vm/vm.cpp +++ b/game/system/vm/vm.cpp @@ -25,6 +25,11 @@ std::mutex status_mutex; int components = 0; } // namespace +static void vm_change_status(Status new_status) { + std::unique_lock lk(status_mutex); + status = new_status; +} + void wait_vm_init() { std::unique_lock lk(status_mutex); @@ -32,9 +37,13 @@ void wait_vm_init() { } void wait_vm_dead() { + if (status != Status::Kill && status != Status::Dead) { + lg::warn("[VM] Dying without being killed! There are {} component(s) running", components); + } + std::unique_lock lk(status_mutex); - vm_dead_cv.wait(lk, [&] { return status == Status::Dead; }); + vm_dead_cv.wait(lk, [&] { return components == 0; }); } bool vm_want_exit() { @@ -43,10 +52,7 @@ bool vm_want_exit() { void vm_prepare() { lg::debug("[VM] Preparing..."); - { - std::unique_lock lk(status_mutex); - status = Status::Uninited; - } + vm_change_status(Status::Uninited); lg::debug("[VM] Prepared"); } @@ -56,26 +62,26 @@ void vm_init() { } lg::debug("[VM] Inited"); - { - std::unique_lock lk(status_mutex); - status = Status::Inited; - } + vm_change_status(Status::Inited); vm_init_cv.notify_all(); } void vm_kill() { lg::debug("[VM] Killing"); - { - std::unique_lock lk(status_mutex); - status = Status::Kill; - } + vm_change_status(Status::Kill); // stall caller until VM is done dying wait_vm_dead(); + + vm_change_status(Status::Dead); } void subscribe_component() { + if (status == Status::Dead) { + throw std::runtime_error("[VM] Cannot add new components when VM is dead!"); + } + ++components; // stall component until VM is ready @@ -86,15 +92,7 @@ void subscribe_component() { void unsubscribe_component() { --components; - - // the VM is "killed" when there's no more components running - if (status == Status::Kill && components == 0) { - { - std::unique_lock lk(status_mutex); - status = Status::Dead; - } - vm_dead_cv.notify_all(); - } + vm_dead_cv.notify_all(); } /*!