1
0
Fork 0

LuaState: Implemented proper locking for cCallback.

This commit is contained in:
Mattes D 2016-06-12 16:53:24 +02:00
parent fb4c3fc4d9
commit 24853397ef
11 changed files with 151 additions and 115 deletions

View File

@ -113,12 +113,10 @@ void cLuaChunkStay::AddChunkCoord(cLuaState & L, int a_Index)
void cLuaChunkStay::Enable(cChunkMap & a_ChunkMap, int a_OnChunkAvailableStackPos, int a_OnAllChunksAvailableStackPos) void cLuaChunkStay::Enable(cChunkMap & a_ChunkMap, cLuaState::cCallbackPtr a_OnChunkAvailable, cLuaState::cCallbackPtr a_OnAllChunksAvailable)
{ {
// Get the references to the callback functions: m_OnChunkAvailable = a_OnChunkAvailable;
m_LuaState = &m_Plugin.GetLuaState(); m_OnAllChunksAvailable = a_OnAllChunksAvailable;
m_OnChunkAvailable.RefStack(*m_LuaState, a_OnChunkAvailableStackPos);
m_OnAllChunksAvailable.RefStack(*m_LuaState, a_OnAllChunksAvailableStackPos);
// Enable the ChunkStay: // Enable the ChunkStay:
super::Enable(a_ChunkMap); super::Enable(a_ChunkMap);
@ -130,10 +128,9 @@ void cLuaChunkStay::Enable(cChunkMap & a_ChunkMap, int a_OnChunkAvailableStackPo
void cLuaChunkStay::OnChunkAvailable(int a_ChunkX, int a_ChunkZ) void cLuaChunkStay::OnChunkAvailable(int a_ChunkX, int a_ChunkZ)
{ {
if (m_OnChunkAvailable.IsValid()) if (m_OnChunkAvailable != nullptr)
{ {
cPluginLua::cOperation Op(m_Plugin); m_OnChunkAvailable->Call(a_ChunkX, a_ChunkZ);
Op().Call(static_cast<int>(m_OnChunkAvailable), a_ChunkX, a_ChunkZ);
} }
} }
@ -143,15 +140,14 @@ void cLuaChunkStay::OnChunkAvailable(int a_ChunkX, int a_ChunkZ)
bool cLuaChunkStay::OnAllChunksAvailable(void) bool cLuaChunkStay::OnAllChunksAvailable(void)
{ {
if (m_OnAllChunksAvailable.IsValid()) if (m_OnAllChunksAvailable != nullptr)
{ {
// Call the callback: // Call the callback:
cPluginLua::cOperation Op(m_Plugin); m_OnAllChunksAvailable->Call();
Op().Call(static_cast<int>(m_OnAllChunksAvailable));
// Remove the callback references - they won't be needed anymore // Remove the callback references - they won't be needed anymore
m_OnChunkAvailable.UnRef(); m_OnChunkAvailable.reset();
m_OnAllChunksAvailable.UnRef(); m_OnAllChunksAvailable.reset();
} }
// Disable the ChunkStay by returning true // Disable the ChunkStay by returning true

View File

@ -39,7 +39,7 @@ public:
bool AddChunks(int a_ChunkCoordTableStackPos); bool AddChunks(int a_ChunkCoordTableStackPos);
/** Enables the ChunkStay for the specified chunkmap, with the specified Lua callbacks. */ /** Enables the ChunkStay for the specified chunkmap, with the specified Lua callbacks. */
void Enable(cChunkMap & a_ChunkMap, int a_OnChunkAvailableStackPos, int a_OnAllChunksAvailableStackPos); void Enable(cChunkMap & a_ChunkMap, cLuaState::cCallbackPtr a_OnChunkAvailable, cLuaState::cCallbackPtr a_OnAllChunksAvailable);
protected: protected:
/** The plugin which has created the ChunkStay, via cWorld:ChunkStay() binding method. */ /** The plugin which has created the ChunkStay, via cWorld:ChunkStay() binding method. */
@ -49,10 +49,10 @@ protected:
cLuaState * m_LuaState; cLuaState * m_LuaState;
/** The Lua function to call in OnChunkAvailable. Only valid when enabled. */ /** The Lua function to call in OnChunkAvailable. Only valid when enabled. */
cLuaState::cRef m_OnChunkAvailable; cLuaState::cCallbackPtr m_OnChunkAvailable;
/** The Lua function to call in OnAllChunksAvailable. Only valid when enabled. */ /** The Lua function to call in OnAllChunksAvailable. Only valid when enabled. */
cLuaState::cRef m_OnAllChunksAvailable; cLuaState::cCallbackPtr m_OnAllChunksAvailable;
// cChunkStay overrides: // cChunkStay overrides:

View File

@ -12,7 +12,7 @@
cLuaNameLookup::cLuaNameLookup(const AString & a_Query, cPluginLua & a_Plugin, int a_CallbacksTableStackPos): cLuaNameLookup::cLuaNameLookup(const AString & a_Query, cPluginLua & a_Plugin, int a_CallbacksTableStackPos):
m_Plugin(a_Plugin), m_Plugin(a_Plugin),
m_Callbacks(a_Plugin.GetLuaState(), a_CallbacksTableStackPos), m_Callbacks(cPluginLua::cOperation(a_Plugin)(), a_CallbacksTableStackPos),
m_Query(a_Query) m_Query(a_Query)
{ {
} }

View File

@ -14,7 +14,7 @@
cLuaServerHandle::cLuaServerHandle(UInt16 a_Port, cPluginLua & a_Plugin, int a_CallbacksTableStackPos): cLuaServerHandle::cLuaServerHandle(UInt16 a_Port, cPluginLua & a_Plugin, int a_CallbacksTableStackPos):
m_Plugin(a_Plugin), m_Plugin(a_Plugin),
m_Callbacks(a_Plugin.GetLuaState(), a_CallbacksTableStackPos), m_Callbacks(cPluginLua::cOperation(a_Plugin)(), a_CallbacksTableStackPos),
m_Port(a_Port) m_Port(a_Port)
{ {
} }

View File

@ -124,6 +124,15 @@ cLuaStateTracker & cLuaStateTracker::Get(void)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// cLuaState::cCallback: // cLuaState::cCallback:
cLuaState::cCallback::cCallback(void):
m_CS(nullptr)
{
}
bool cLuaState::cCallback::RefStack(cLuaState & a_LuaState, int a_StackPos) bool cLuaState::cCallback::RefStack(cLuaState & a_LuaState, int a_StackPos)
{ {
// Check if the stack contains a function: // Check if the stack contains a function:
@ -136,11 +145,12 @@ bool cLuaState::cCallback::RefStack(cLuaState & a_LuaState, int a_StackPos)
Clear(); Clear();
// Add self to LuaState's callback-tracking: // Add self to LuaState's callback-tracking:
a_LuaState.TrackCallback(*this); auto canonState = a_LuaState.QueryCanonLuaState();
canonState->TrackCallback(*this);
// Store the new callback: // Store the new callback:
cCSLock Lock(m_CS); m_CS = &(canonState->m_CS);
m_Ref.RefStack(a_LuaState, a_StackPos); m_Ref.RefStack(*canonState, a_StackPos);
return true; return true;
} }
@ -153,16 +163,24 @@ void cLuaState::cCallback::Clear(void)
// Free the callback reference: // Free the callback reference:
lua_State * luaState = nullptr; lua_State * luaState = nullptr;
{ {
cCSLock Lock(m_CS); auto cs = m_CS;
if (!m_Ref.IsValid()) if (cs != nullptr)
{ {
return; cCSLock Lock(*cs);
if (!m_Ref.IsValid())
{
return;
}
luaState = m_Ref.GetLuaState();
m_Ref.UnRef();
} }
luaState = m_Ref.GetLuaState();
m_Ref.UnRef();
} }
// Remove from LuaState's callback-tracking: // Remove from LuaState's callback-tracking:
if (luaState == nullptr)
{
return;
}
cLuaState(luaState).UntrackCallback(*this); cLuaState(luaState).UntrackCallback(*this);
} }
@ -172,7 +190,12 @@ void cLuaState::cCallback::Clear(void)
bool cLuaState::cCallback::IsValid(void) bool cLuaState::cCallback::IsValid(void)
{ {
cCSLock lock(m_CS); auto cs = m_CS;
if (cs == nullptr)
{
return false;
}
cCSLock lock(*cs);
return m_Ref.IsValid(); return m_Ref.IsValid();
} }
@ -182,7 +205,12 @@ bool cLuaState::cCallback::IsValid(void)
bool cLuaState::cCallback::IsSameLuaState(cLuaState & a_LuaState) bool cLuaState::cCallback::IsSameLuaState(cLuaState & a_LuaState)
{ {
cCSLock lock(m_CS); auto cs = m_CS;
if (cs == nullptr)
{
return false;
}
cCSLock lock(*cs);
if (!m_Ref.IsValid()) if (!m_Ref.IsValid())
{ {
return false; return false;
@ -201,10 +229,16 @@ bool cLuaState::cCallback::IsSameLuaState(cLuaState & a_LuaState)
void cLuaState::cCallback::Invalidate(void) void cLuaState::cCallback::Invalidate(void)
{ {
cCSLock Lock(m_CS); auto cs = m_CS;
if (cs == nullptr)
{
// Already invalid
return;
}
cCSLock Lock(*cs);
if (!m_Ref.IsValid()) if (!m_Ref.IsValid())
{ {
LOGD("%s: Invalidating an already invalid callback at %p, this should not happen", LOGD("%s: Inconsistent callback at %p, has a CS but an invalid Ref. This should not happen",
__FUNCTION__, reinterpret_cast<void *>(this) __FUNCTION__, reinterpret_cast<void *>(this)
); );
return; return;

View File

@ -7,7 +7,7 @@
The contained lua_State can be either owned or attached. The contained lua_State can be either owned or attached.
Owned lua_State is created by calling Create() and the cLuaState automatically closes the state Owned lua_State is created by calling Create() and the cLuaState automatically closes the state
Or, lua_State can be attached by calling Attach(), the cLuaState doesn't close such a state Or, lua_State can be attached by calling Attach(), the cLuaState doesn't close such a state
Attaching a state will automatically close an owned state. If owning a state, trying to attach a state will automatically close the previously owned state.
Calling a Lua function is done internally by pushing the function using PushFunction(), then pushing the Calling a Lua function is done internally by pushing the function using PushFunction(), then pushing the
arguments and finally executing CallFunction(). cLuaState automatically keeps track of the number of arguments and finally executing CallFunction(). cLuaState automatically keeps track of the number of
@ -16,8 +16,12 @@ the stack using GetStackValue(). All of this is wrapped in a templated function
which is generated automatically by gen_LuaState_Call.lua script file into the LuaState_Call.inc file. which is generated automatically by gen_LuaState_Call.lua script file into the LuaState_Call.inc file.
Reference management is provided by the cLuaState::cRef class. This is used when you need to hold a reference to Reference management is provided by the cLuaState::cRef class. This is used when you need to hold a reference to
any Lua object across several function calls; usually this is used for callbacks. The class is RAII-like, with any Lua object across several function calls. The class is RAII-like, with automatic resource management.
automatic resource management.
Callbacks management is provided by the cLuaState::cCallback class. Use a GetStackValue() with cCallbackPtr
parameter to store the callback, and then at any time you can use the cCallback's Call() templated function
to call the callback. The callback management takes care of cLuaState being destroyed - the cCallback object
stays valid but doesn't call into Lua code anymore, returning false for "failure" instead.
*/ */
@ -39,6 +43,7 @@ extern "C"
class cLuaServerHandle; class cLuaServerHandle;
class cLuaTCPLink; class cLuaTCPLink;
class cLuaUDPEndpoint; class cLuaUDPEndpoint;
class cPluginLua;
@ -49,6 +54,20 @@ class cLuaState
{ {
public: public:
/** Provides a RAII-style locking for the LuaState.
Used mainly by the cPluginLua internals to provide the actual locking for interface operations, such as callbacks. */
class cLock
{
public:
cLock(cLuaState & a_LuaState):
m_Lock(a_LuaState.m_CS)
{
}
protected:
cCSLock m_Lock;
};
/** Used for storing references to object in the global registry. /** Used for storing references to object in the global registry.
Can be bound (contains a reference) or unbound (doesn't contain reference). Can be bound (contains a reference) or unbound (doesn't contain reference).
The reference can also be reset by calling RefStack(). */ The reference can also be reset by calling RefStack(). */
@ -127,15 +146,15 @@ public:
/** Represents a callback to Lua that C++ code can call. /** Represents a callback to Lua that C++ code can call.
Is thread-safe and unload-safe. Is thread-safe and unload-safe.
When the Lua state is unloaded, the callback returns an error instead of calling into non-existent code. When the Lua state is unloaded, the callback returns an error instead of calling into non-existent code.
To receive the callback instance from the Lua side, use RefStack() or (better) cLuaState::GetStackValue(). To receive the callback instance from the Lua side, use RefStack() or (better) cLuaState::GetStackValue()
Note that instances of this class are tracked in the canon LuaState instance, so that they can be invalidated with a cCallbackPtr. Note that instances of this class are tracked in the canon LuaState instance, so that
when the LuaState is unloaded; due to multithreading issues they can only be tracked by-ptr, which has they can be invalidated when the LuaState is unloaded; due to multithreading issues they can only be tracked
an unfortunate effect of disabling the copy and move constructors. */ by-ptr, which has an unfortunate effect of disabling the copy and move constructors. */
class cCallback class cCallback
{ {
public: public:
/** Creates an unbound callback instance. */ /** Creates an unbound callback instance. */
cCallback(void) = default; cCallback(void);
~cCallback() ~cCallback()
{ {
@ -148,13 +167,17 @@ public:
template <typename... Args> template <typename... Args>
bool Call(Args &&... args) bool Call(Args &&... args)
{ {
cCSLock Lock(m_CS); auto cs = m_CS;
if (cs == nullptr)
{
return false;
}
cCSLock Lock(*cs);
if (!m_Ref.IsValid()) if (!m_Ref.IsValid())
{ {
return false; return false;
} }
cLuaState(m_Ref.GetLuaState()).Call(m_Ref, std::forward<Args>(args)...); return cLuaState(m_Ref.GetLuaState()).Call(m_Ref, std::forward<Args>(args)...);
return true;
} }
/** Set the contained callback to the function in the specified Lua state's stack position. /** Set the contained callback to the function in the specified Lua state's stack position.
@ -175,7 +198,7 @@ public:
friend class cLuaState; friend class cLuaState;
/** The mutex protecting m_Ref against multithreaded access */ /** The mutex protecting m_Ref against multithreaded access */
cCriticalSection m_CS; cCriticalSection * m_CS;
/** Reference to the Lua callback */ /** Reference to the Lua callback */
cRef m_Ref; cRef m_Ref;
@ -185,10 +208,12 @@ public:
Called only from cLuaState when closing the Lua state. */ Called only from cLuaState when closing the Lua state. */
void Invalidate(void); void Invalidate(void);
/** This class cannot be copied, because it is tracked in the LuaState by-ptr. */ /** This class cannot be copied, because it is tracked in the LuaState by-ptr.
Use cCallbackPtr for a copyable object. */
cCallback(const cCallback &) = delete; cCallback(const cCallback &) = delete;
/** This class cannot be moved, because it is tracked in the LuaState by-ptr. */ /** This class cannot be moved, because it is tracked in the LuaState by-ptr.
Use cCallbackPtr for a copyable object. */
cCallback(cCallback &&) = delete; cCallback(cCallback &&) = delete;
}; };
typedef SharedPtr<cCallback> cCallbackPtr; typedef SharedPtr<cCallback> cCallbackPtr;
@ -250,6 +275,8 @@ public:
protected: protected:
lua_State * m_LuaState; lua_State * m_LuaState;
/** Used for debugging, Lua state's stack size is checked against this number to make sure
it is the same as when the value was pushed. */
int m_StackLen; int m_StackLen;
// Remove the copy-constructor: // Remove the copy-constructor:
@ -538,6 +565,8 @@ public:
protected: protected:
cCriticalSection m_CS;
lua_State * m_LuaState; lua_State * m_LuaState;
/** If true, the state is owned by this object and will be auto-Closed. False => attached state */ /** If true, the state is owned by this object and will be auto-Closed. False => attached state */

View File

@ -13,7 +13,7 @@
cLuaTCPLink::cLuaTCPLink(cPluginLua & a_Plugin, int a_CallbacksTableStackPos): cLuaTCPLink::cLuaTCPLink(cPluginLua & a_Plugin, int a_CallbacksTableStackPos):
m_Plugin(a_Plugin), m_Plugin(a_Plugin),
m_Callbacks(a_Plugin.GetLuaState(), a_CallbacksTableStackPos) m_Callbacks(cPluginLua::cOperation(a_Plugin)(), a_CallbacksTableStackPos)
{ {
// Warn if the callbacks aren't valid: // Warn if the callbacks aren't valid:
if (!m_Callbacks.IsValid()) if (!m_Callbacks.IsValid())

View File

@ -12,7 +12,7 @@
cLuaUDPEndpoint::cLuaUDPEndpoint(cPluginLua & a_Plugin, int a_CallbacksTableStackPos): cLuaUDPEndpoint::cLuaUDPEndpoint(cPluginLua & a_Plugin, int a_CallbacksTableStackPos):
m_Plugin(a_Plugin), m_Plugin(a_Plugin),
m_Callbacks(a_Plugin.GetLuaState(), a_CallbacksTableStackPos) m_Callbacks(cPluginLua::cOperation(a_Plugin)(), a_CallbacksTableStackPos)
{ {
// Warn if the callbacks aren't valid: // Warn if the callbacks aren't valid:
if (!m_Callbacks.IsValid()) if (!m_Callbacks.IsValid())

View File

@ -103,7 +103,9 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S)
return 0; return 0;
} }
ChunkStay->Enable(*World->GetChunkMap(), 3, 4); cLuaState::cCallbackPtr onChunkAvailable, onAllChunksAvailable;
L.GetStackValues(3, onChunkAvailable, onAllChunksAvailable); // Callbacks may be unassigned at all - as a request to load / generate chunks
ChunkStay->Enable(*World->GetChunkMap(), onChunkAvailable, onAllChunksAvailable);
return 0; return 0;
} }

View File

@ -45,7 +45,6 @@ cPluginLua::cPluginLua(const AString & a_PluginDirectory) :
cPluginLua::~cPluginLua() cPluginLua::~cPluginLua()
{ {
cCSLock Lock(m_CriticalSection);
Close(); Close();
} }
@ -55,10 +54,9 @@ cPluginLua::~cPluginLua()
void cPluginLua::Close(void) void cPluginLua::Close(void)
{ {
cCSLock Lock(m_CriticalSection); cOperation op(*this);
// If already closed, bail out: // If already closed, bail out:
if (!m_LuaState.IsValid()) if (!op().IsValid())
{ {
ASSERT(m_HookMap.empty()); ASSERT(m_HookMap.empty());
return; return;
@ -73,7 +71,7 @@ void cPluginLua::Close(void)
m_HookMap.clear(); m_HookMap.clear();
// Close the Lua engine: // Close the Lua engine:
m_LuaState.Close(); op().Close();
} }
@ -82,8 +80,8 @@ void cPluginLua::Close(void)
bool cPluginLua::Load(void) bool cPluginLua::Load(void)
{ {
cCSLock Lock(m_CriticalSection); cOperation op(*this);
if (!m_LuaState.IsValid()) if (!op().IsValid())
{ {
m_LuaState.Create(); m_LuaState.Create();
m_LuaState.RegisterAPILibs(); m_LuaState.RegisterAPILibs();
@ -198,12 +196,12 @@ void cPluginLua::Unload(void)
void cPluginLua::OnDisable(void) void cPluginLua::OnDisable(void)
{ {
cCSLock Lock(m_CriticalSection); cOperation op(*this);
if (!m_LuaState.HasFunction("OnDisable")) if (!op().HasFunction("OnDisable"))
{ {
return; return;
} }
m_LuaState.Call("OnDisable"); op().Call("OnDisable");
} }
@ -257,8 +255,8 @@ bool cPluginLua::OnBrewingCompleting(cWorld & a_World, cBrewingstandEntity & a_B
bool cPluginLua::OnChat(cPlayer & a_Player, AString & a_Message) bool cPluginLua::OnChat(cPlayer & a_Player, AString & a_Message)
{ {
cCSLock Lock(m_CriticalSection); cOperation op(*this);
if (!m_LuaState.IsValid()) if (!op().IsValid())
{ {
return false; return false;
} }
@ -380,8 +378,8 @@ bool cPluginLua::OnEntityChangedWorld(cEntity & a_Entity, cWorld & a_World)
bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split, const AString & a_EntireCommand, cPluginManager::CommandResult & a_Result) bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split, const AString & a_EntireCommand, cPluginManager::CommandResult & a_Result)
{ {
cCSLock Lock(m_CriticalSection); cOperation op(*this);
if (!m_LuaState.IsValid()) if (!op().IsValid())
{ {
return false; return false;
} }
@ -404,8 +402,8 @@ bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Sp
bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData)
{ {
cCSLock Lock(m_CriticalSection); cOperation op(*this);
if (!m_LuaState.IsValid()) if (!op().IsValid())
{ {
return false; return false;
} }
@ -444,8 +442,8 @@ bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_Can
bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData)
{ {
cCSLock Lock(m_CriticalSection); cOperation op(*this);
if (!m_LuaState.IsValid()) if (!op().IsValid())
{ {
return false; return false;
} }
@ -511,8 +509,8 @@ bool cPluginLua::OnHopperPushingItem(cWorld & a_World, cHopperEntity & a_Hopper,
bool cPluginLua::OnKilled(cEntity & a_Victim, TakeDamageInfo & a_TDI, AString & a_DeathMessage) bool cPluginLua::OnKilled(cEntity & a_Victim, TakeDamageInfo & a_TDI, AString & a_DeathMessage)
{ {
cCSLock Lock(m_CriticalSection); cOperation op(*this);
if (!m_LuaState.IsValid()) if (!op().IsValid())
{ {
return false; return false;
} }
@ -777,8 +775,8 @@ bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Cha
bool cPluginLua::OnPluginsLoaded(void) bool cPluginLua::OnPluginsLoaded(void)
{ {
cCSLock Lock(m_CriticalSection); cOperation op(*this);
if (!m_LuaState.IsValid()) if (!op().IsValid())
{ {
return false; return false;
} }
@ -835,8 +833,8 @@ bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity
bool cPluginLua::OnServerPing(cClientHandle & a_ClientHandle, AString & a_ServerDescription, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) bool cPluginLua::OnServerPing(cClientHandle & a_ClientHandle, AString & a_ServerDescription, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon)
{ {
cCSLock Lock(m_CriticalSection); cOperation op(*this);
if (!m_LuaState.IsValid()) if (!op().IsValid())
{ {
return false; return false;
} }
@ -923,8 +921,8 @@ bool cPluginLua::OnUpdatingSign(
cPlayer * a_Player cPlayer * a_Player
) )
{ {
cCSLock Lock(m_CriticalSection); cOperation op(*this);
if (!m_LuaState.IsValid()) if (!op().IsValid())
{ {
return false; return false;
} }
@ -956,8 +954,8 @@ bool cPluginLua::OnWeatherChanged(cWorld & a_World)
bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather) bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather)
{ {
cCSLock Lock(m_CriticalSection); cOperation op(*this);
if (!m_LuaState.IsValid()) if (!op().IsValid())
{ {
return false; return false;
} }
@ -999,6 +997,7 @@ bool cPluginLua::OnWorldTick(cWorld & a_World, std::chrono::milliseconds a_Dt, s
bool cPluginLua::HandleCommand(const AStringVector & a_Split, cPlayer & a_Player, const AString & a_FullCommand) bool cPluginLua::HandleCommand(const AStringVector & a_Split, cPlayer & a_Player, const AString & a_FullCommand)
{ {
ASSERT(!a_Split.empty()); ASSERT(!a_Split.empty());
cOperation op(*this);
CommandMap::iterator cmd = m_Commands.find(a_Split[0]); CommandMap::iterator cmd = m_Commands.find(a_Split[0]);
if (cmd == m_Commands.end()) if (cmd == m_Commands.end())
{ {
@ -1006,9 +1005,8 @@ bool cPluginLua::HandleCommand(const AStringVector & a_Split, cPlayer & a_Player
return false; return false;
} }
cCSLock Lock(m_CriticalSection);
bool res = false; bool res = false;
m_LuaState.Call(cmd->second, a_Split, &a_Player, a_FullCommand, cLuaState::Return, res); op().Call(cmd->second, a_Split, &a_Player, a_FullCommand, cLuaState::Return, res);
return res; return res;
} }
@ -1019,6 +1017,7 @@ bool cPluginLua::HandleCommand(const AStringVector & a_Split, cPlayer & a_Player
bool cPluginLua::HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_FullCommand) bool cPluginLua::HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_FullCommand)
{ {
ASSERT(!a_Split.empty()); ASSERT(!a_Split.empty());
cOperation op(*this);
CommandMap::iterator cmd = m_ConsoleCommands.find(a_Split[0]); CommandMap::iterator cmd = m_ConsoleCommands.find(a_Split[0]);
if (cmd == m_ConsoleCommands.end()) if (cmd == m_ConsoleCommands.end())
{ {
@ -1028,10 +1027,9 @@ bool cPluginLua::HandleConsoleCommand(const AStringVector & a_Split, cCommandOut
return false; return false;
} }
cCSLock Lock(m_CriticalSection);
bool res = false; bool res = false;
AString str; AString str;
m_LuaState.Call(cmd->second, a_Split, a_FullCommand, cLuaState::Return, res, str); op().Call(cmd->second, a_Split, a_FullCommand, cLuaState::Return, res, str);
if (res && !str.empty()) if (res && !str.empty())
{ {
a_Output.Out(str); a_Output.Out(str);
@ -1045,7 +1043,7 @@ bool cPluginLua::HandleConsoleCommand(const AStringVector & a_Split, cCommandOut
void cPluginLua::ClearCommands(void) void cPluginLua::ClearCommands(void)
{ {
cCSLock Lock(m_CriticalSection); cOperation op(*this);
// Unreference the bound functions so that Lua can GC them // Unreference the bound functions so that Lua can GC them
if (m_LuaState != nullptr) if (m_LuaState != nullptr)
@ -1064,7 +1062,7 @@ void cPluginLua::ClearCommands(void)
void cPluginLua::ClearConsoleCommands(void) void cPluginLua::ClearConsoleCommands(void)
{ {
cCSLock Lock(m_CriticalSection); cOperation op(*this);
// Unreference the bound functions so that Lua can GC them // Unreference the bound functions so that Lua can GC them
if (m_LuaState != nullptr) if (m_LuaState != nullptr)
@ -1187,8 +1185,6 @@ const char * cPluginLua::GetHookFnName(int a_HookType)
bool cPluginLua::AddHookCallback(int a_HookType, cLuaState::cCallbackPtr a_Callback) bool cPluginLua::AddHookCallback(int a_HookType, cLuaState::cCallbackPtr a_Callback)
{ {
ASSERT(m_CriticalSection.IsLockedByCurrentThread()); // It probably has to be, how else would we have a LuaState?
m_HookMap[a_HookType].push_back(a_Callback); m_HookMap[a_HookType].push_back(a_Callback);
return true; return true;
} }
@ -1204,10 +1200,10 @@ int cPluginLua::CallFunctionFromForeignState(
int a_ParamEnd int a_ParamEnd
) )
{ {
cCSLock Lock(m_CriticalSection); cOperation op(*this);
// Call the function: // Call the function:
int NumReturns = m_LuaState.CallFunctionWithForeignParams(a_FunctionName, a_ForeignState, a_ParamStart, a_ParamEnd); int NumReturns = op().CallFunctionWithForeignParams(a_FunctionName, a_ForeignState, a_ParamStart, a_ParamEnd);
if (NumReturns < 0) if (NumReturns < 0)
{ {
// The call has failed, an error has already been output to the log, so just silently bail out with the same error // The call has failed, an error has already been output to the log, so just silently bail out with the same error
@ -1251,23 +1247,13 @@ void cPluginLua::BindConsoleCommand(const AString & a_Command, int a_FnRef)
void cPluginLua::Unreference(int a_LuaRef)
{
cCSLock Lock(m_CriticalSection);
luaL_unref(m_LuaState, LUA_REGISTRYINDEX, a_LuaRef);
}
bool cPluginLua::CallbackWindowClosing(int a_FnRef, cWindow & a_Window, cPlayer & a_Player, bool a_CanRefuse) bool cPluginLua::CallbackWindowClosing(int a_FnRef, cWindow & a_Window, cPlayer & a_Player, bool a_CanRefuse)
{ {
ASSERT(a_FnRef != LUA_REFNIL); ASSERT(a_FnRef != LUA_REFNIL);
cCSLock Lock(m_CriticalSection); cOperation op(*this);
bool res = false; bool res = false;
m_LuaState.Call(a_FnRef, &a_Window, &a_Player, a_CanRefuse, cLuaState::Return, res); op().Call(a_FnRef, &a_Window, &a_Player, a_CanRefuse, cLuaState::Return, res);
return res; return res;
} }
@ -1279,8 +1265,8 @@ void cPluginLua::CallbackWindowSlotChanged(int a_FnRef, cWindow & a_Window, int
{ {
ASSERT(a_FnRef != LUA_REFNIL); ASSERT(a_FnRef != LUA_REFNIL);
cCSLock Lock(m_CriticalSection); cOperation op(*this);
m_LuaState.Call(a_FnRef, &a_Window, a_SlotNum); op().Call(a_FnRef, &a_Window, a_SlotNum);
} }

View File

@ -47,7 +47,7 @@ public:
public: public:
cOperation(cPluginLua & a_Plugin) : cOperation(cPluginLua & a_Plugin) :
m_Plugin(a_Plugin), m_Plugin(a_Plugin),
m_Lock(a_Plugin.m_CriticalSection) m_Lock(a_Plugin.m_LuaState)
{ {
} }
@ -56,8 +56,8 @@ public:
protected: protected:
cPluginLua & m_Plugin; cPluginLua & m_Plugin;
/** RAII lock for m_Plugin.m_CriticalSection */ /** RAII lock for the Lua state. */
cCSLock m_Lock; cLuaState::cLock m_Lock;
} ; } ;
@ -155,13 +155,6 @@ public:
/** Binds the console command to call the function specified by a Lua function reference. Simply adds to CommandMap. */ /** Binds the console command to call the function specified by a Lua function reference. Simply adds to CommandMap. */
void BindConsoleCommand(const AString & a_Command, int a_FnRef); void BindConsoleCommand(const AString & a_Command, int a_FnRef);
cLuaState & GetLuaState(void) { return m_LuaState; }
cCriticalSection & GetCriticalSection(void) { return m_CriticalSection; }
/** Removes a previously referenced object (luaL_unref()) */
void Unreference(int a_LuaRef);
/** Calls the plugin-specified "cLuaWindow closing" callback. Returns true only if the callback returned true */ /** Calls the plugin-specified "cLuaWindow closing" callback. Returns true only if the callback returned true */
bool CallbackWindowClosing(int a_FnRef, cWindow & a_Window, cPlayer & a_Player, bool a_CanRefuse); bool CallbackWindowClosing(int a_FnRef, cWindow & a_Window, cPlayer & a_Player, bool a_CanRefuse);
@ -189,8 +182,7 @@ public:
template <typename FnT, typename... Args> template <typename FnT, typename... Args>
bool Call(FnT a_Fn, Args && ... a_Args) bool Call(FnT a_Fn, Args && ... a_Args)
{ {
cCSLock Lock(m_CriticalSection); return cOperation(*this)().Call(a_Fn, a_Args...);
return m_LuaState.Call(a_Fn, a_Args...);
} }
protected: protected:
@ -204,9 +196,6 @@ protected:
typedef std::map<int, cLuaCallbacks> cHookMap; typedef std::map<int, cLuaCallbacks> cHookMap;
/** The mutex protecting m_LuaState against multithreaded use. */
cCriticalSection m_CriticalSection;
/** The plugin's Lua state. */ /** The plugin's Lua state. */
cLuaState m_LuaState; cLuaState m_LuaState;
@ -232,7 +221,7 @@ protected:
template <typename... Args> template <typename... Args>
bool CallSimpleHooks(int a_HookType, Args && ... a_Args) bool CallSimpleHooks(int a_HookType, Args && ... a_Args)
{ {
cCSLock lock(m_CriticalSection); cOperation op(*this);
auto & hooks = m_HookMap[a_HookType]; auto & hooks = m_HookMap[a_HookType];
bool res = false; bool res = false;
for (auto & hook: hooks) for (auto & hook: hooks)