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.
develop
Alexander Gavrilov 2012-08-18 11:52:38 +04:00
parent 01ba2a31fc
commit 24cc8b5c7a
3 changed files with 78 additions and 27 deletions

@ -1027,35 +1027,41 @@ int Core::TileUpdate()
return true; return true;
} }
// should always be from simulation thread! int Core::ClaimSuspend(bool force_base)
int Core::Update()
{ {
if(errorstate) auto tid = this_thread::get_id();
return -1; 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); assert(d->df_suspend_depth == 0);
d->df_suspend_thread = this_thread::get_id();
d->df_suspend_depth = 1000;
}
// Initialize the core d->df_suspend_thread = tid;
bool first_update = false; d->df_suspend_depth = 1000000;
return 1000000;
if(!started) }
else
{ {
first_update = true; assert(d->df_suspend_thread == tid);
Init(); return ++d->df_suspend_depth;
if(errorstate)
return -1;
Lua::Core::Reset(con, "core init");
} }
}
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"); Lua::Core::Reset(out, "DF code execution");
if (first_update) if (first_update)
@ -1129,15 +1135,36 @@ int Core::Update()
// Execute per-frame handlers // Execute per-frame handlers
onUpdate(out); 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); // Initialize the core
d->df_suspend_depth = 0; 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 // wake waiting tools
// do not allow more tools to join in while we process stuff here // do not allow more tools to join in while we process stuff here
@ -1158,7 +1185,7 @@ int Core::Update()
// destroy condition // destroy condition
delete nc; delete nc;
// check lua stack depth // check lua stack depth
Lua::Core::Reset(con, "suspend"); Lua::Core::Reset(out, "suspend");
} }
return 0; return 0;

@ -174,6 +174,10 @@ namespace DFHack
struct Private; struct Private;
Private *d; Private *d;
friend class CoreSuspendClaimer;
int ClaimSuspend(bool force_base);
void DisclaimSuspend(int level);
bool Init(); bool Init();
int Update (void); int Update (void);
int TileUpdate (void); int TileUpdate (void);
@ -181,6 +185,7 @@ namespace DFHack
int DFH_SDL_Event(SDL::Event* event); int DFH_SDL_Event(SDL::Event* event);
bool ncurses_wgetch(int in, int & out); bool ncurses_wgetch(int in, int & out);
void doUpdate(color_ostream &out, bool first_update);
void onUpdate(color_ostream &out); void onUpdate(color_ostream &out);
void onStateChange(color_ostream &out, state_change_event event); void onStateChange(color_ostream &out, state_change_event event);
@ -249,4 +254,20 @@ namespace DFHack
CoreSuspender(Core *core) : core(core) { core->Suspend(); } CoreSuspender(Core *core) : core(core) { core->Suspend(); }
~CoreSuspender() { core->Resume(); } ~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); }
};
} }

@ -95,6 +95,9 @@ namespace DFHack
typedef df::someclass interpose_base; typedef df::someclass interpose_base;
DEFINE_VMETHOD_INTERPOSE(void, foo, (int arg)) { 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 INTERPOSE_NEXT(foo)(arg) // call the original
... ...