summaryrefslogtreecommitdiff
path: root/library
diff options
context:
space:
mode:
authorAlexander Gavrilov2012-08-18 11:52:38 +0400
committerAlexander Gavrilov2012-08-18 11:52:38 +0400
commit24cc8b5c7add7e18b6bd42eea743a9e9d562a336 (patch)
treecc039bcc2e032ac2a8639929693caed1b66e7638 /library
parent01ba2a31fc2dd7597ab6e2db3f1496b123e10720 (diff)
downloaddfhack-24cc8b5c7add7e18b6bd42eea743a9e9d562a336.tar.gz
dfhack-24cc8b5c7add7e18b6bd42eea743a9e9d562a336.tar.bz2
dfhack-24cc8b5c7add7e18b6bd42eea743a9e9d562a336.tar.xz
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.
Diffstat (limited to 'library')
-rw-r--r--library/Core.cpp81
-rw-r--r--library/include/Core.h21
-rw-r--r--library/include/VTableInterpose.h3
3 files changed, 78 insertions, 27 deletions
diff --git a/library/Core.cpp b/library/Core.cpp
index f129d952..bf0b3be7 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<mutex> lock(d->AccessMutex);
- // Pretend this thread has suspended the core in the usual way
+ if (force_base || d->df_suspend_depth <= 0)
{
- lock_guard<mutex> 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<mutex> 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<mutex> 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 d25beef5..e1f1cf3f 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 5eaeaed8..bb7a37ce 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
...