From 24cc8b5c7add7e18b6bd42eea743a9e9d562a336 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 18 Aug 2012 11:52:38 +0400 Subject: [PATCH] Expose an API to claim the suspend lock from the Core. Previously it was hard-coded in Core::Update, but interposed vmethods may need this feature too. --- library/Core.cpp | 81 ++++++++++++++++++++----------- library/include/Core.h | 21 ++++++++ library/include/VTableInterpose.h | 3 ++ 3 files changed, 78 insertions(+), 27 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index f129d9523..bf0b3be70 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1027,35 +1027,41 @@ int Core::TileUpdate() return true; } -// should always be from simulation thread! -int Core::Update() +int Core::ClaimSuspend(bool force_base) { - if(errorstate) - return -1; + auto tid = this_thread::get_id(); + lock_guard lock(d->AccessMutex); - // Pretend this thread has suspended the core in the usual way + if (force_base || d->df_suspend_depth <= 0) { - lock_guard lock(d->AccessMutex); - assert(d->df_suspend_depth == 0); - d->df_suspend_thread = this_thread::get_id(); - d->df_suspend_depth = 1000; - } - // Initialize the core - bool first_update = false; - - if(!started) + d->df_suspend_thread = tid; + d->df_suspend_depth = 1000000; + return 1000000; + } + else { - first_update = true; - Init(); - if(errorstate) - return -1; - Lua::Core::Reset(con, "core init"); + assert(d->df_suspend_thread == tid); + return ++d->df_suspend_depth; } +} - color_ostream_proxy out(con); +void Core::DisclaimSuspend(int level) +{ + auto tid = this_thread::get_id(); + lock_guard lock(d->AccessMutex); + + assert(d->df_suspend_depth == level && d->df_suspend_thread == tid); + + if (level == 1000000) + d->df_suspend_depth = 0; + else + --d->df_suspend_depth; +} +void Core::doUpdate(color_ostream &out, bool first_update) +{ Lua::Core::Reset(out, "DF code execution"); if (first_update) @@ -1129,15 +1135,36 @@ int Core::Update() // Execute per-frame handlers onUpdate(out); - // Release the fake suspend lock + out << std::flush; +} + +// should always be from simulation thread! +int Core::Update() +{ + if(errorstate) + return -1; + + color_ostream_proxy out(con); + + // Pretend this thread has suspended the core in the usual way, + // and run various processing hooks. { - lock_guard lock(d->AccessMutex); + CoreSuspendClaimer suspend(true); - assert(d->df_suspend_depth == 1000); - d->df_suspend_depth = 0; - } + // Initialize the core + bool first_update = false; - out << std::flush; + if(!started) + { + first_update = true; + Init(); + if(errorstate) + return -1; + Lua::Core::Reset(con, "core init"); + } + + doUpdate(out, first_update); + } // wake waiting tools // do not allow more tools to join in while we process stuff here @@ -1158,7 +1185,7 @@ int Core::Update() // destroy condition delete nc; // check lua stack depth - Lua::Core::Reset(con, "suspend"); + Lua::Core::Reset(out, "suspend"); } return 0; diff --git a/library/include/Core.h b/library/include/Core.h index d25beef5f..e1f1cf3fb 100644 --- a/library/include/Core.h +++ b/library/include/Core.h @@ -174,6 +174,10 @@ namespace DFHack struct Private; Private *d; + friend class CoreSuspendClaimer; + int ClaimSuspend(bool force_base); + void DisclaimSuspend(int level); + bool Init(); int Update (void); int TileUpdate (void); @@ -181,6 +185,7 @@ namespace DFHack int DFH_SDL_Event(SDL::Event* event); bool ncurses_wgetch(int in, int & out); + void doUpdate(color_ostream &out, bool first_update); void onUpdate(color_ostream &out); void onStateChange(color_ostream &out, state_change_event event); @@ -249,4 +254,20 @@ namespace DFHack CoreSuspender(Core *core) : core(core) { core->Suspend(); } ~CoreSuspender() { core->Resume(); } }; + + /** Claims the current thread already has the suspend lock. + * Strictly for use in callbacks from DF. + */ + class CoreSuspendClaimer { + Core *core; + int level; + public: + CoreSuspendClaimer(bool base = false) : core(&Core::getInstance()) { + level = core->ClaimSuspend(base); + } + CoreSuspendClaimer(Core *core, bool base = false) : core(core) { + level = core->ClaimSuspend(base); + } + ~CoreSuspendClaimer() { core->DisclaimSuspend(level); } + }; } diff --git a/library/include/VTableInterpose.h b/library/include/VTableInterpose.h index 5eaeaed85..bb7a37ce8 100644 --- a/library/include/VTableInterpose.h +++ b/library/include/VTableInterpose.h @@ -95,6 +95,9 @@ namespace DFHack typedef df::someclass interpose_base; DEFINE_VMETHOD_INTERPOSE(void, foo, (int arg)) { + // If needed by the code, claim the suspend lock. + // DO NOT USE THE USUAL CoreSuspender, OR IT WILL DEADLOCK! + // CoreSuspendClaimer suspend; ... INTERPOSE_NEXT(foo)(arg) // call the original ...