From 3aa76568232968306e8e2d31878d76f0530a41ea Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 2 Mar 2016 11:34:39 +0100 Subject: Added cLuaState::cCallback for representing (resettable) Lua callbacks. --- src/Bindings/LuaState.cpp | 149 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 145 insertions(+), 4 deletions(-) (limited to 'src/Bindings/LuaState.cpp') diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 200878cf7..8e4f48275 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -20,6 +20,10 @@ extern "C" #include "../Entities/Entity.h" #include "../BlockEntities/BlockEntity.h" + + + + // fwd: "SQLite/lsqlite3.c" extern "C" { @@ -39,6 +43,10 @@ extern "C" const cLuaState::cRet cLuaState::Return = {}; +/** Each Lua state stores a pointer to its creating cLuaState in Lua globals, under this name. +This way any cLuaState can reference the main cLuaState's TrackedCallbacks, mutex etc. */ +static const char * g_CanonLuaStateGlobalName = "_CuberiteInternal_CanonLuaState"; + @@ -113,6 +121,72 @@ cLuaStateTracker & cLuaStateTracker::Get(void) +//////////////////////////////////////////////////////////////////////////////// +// cLuaState::cCallback: + +bool cLuaState::cCallback::RefStack(cLuaState & a_LuaState, int a_StackPos) +{ + // Check if the stack contains a function: + if (!lua_isfunction(a_LuaState, a_StackPos)) + { + return false; + } + + // Clear any previous callback: + Clear(); + + // Add self to LuaState's callback-tracking: + a_LuaState.TrackCallback(*this); + + // Store the new callback: + cCSLock Lock(m_CS); + m_Ref.RefStack(a_LuaState, a_StackPos); + return true; +} + + + + + +void cLuaState::cCallback::Clear(void) +{ + // Free the callback reference: + lua_State * luaState = nullptr; + { + cCSLock Lock(m_CS); + if (!m_Ref.IsValid()) + { + return; + } + luaState = m_Ref.GetLuaState(); + m_Ref.UnRef(); + } + + // Remove from LuaState's callback-tracking: + cLuaState(luaState).UntrackCallback(*this); +} + + + + + +void cLuaState::cCallback::Invalidate(void) +{ + cCSLock Lock(m_CS); + if (!m_Ref.IsValid()) + { + LOGD("%s: Invalidating an already invalid callback at %p, this should not happen", + __FUNCTION__, reinterpret_cast(this) + ); + return; + } + m_Ref.UnRef(); +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cLuaState: @@ -170,6 +244,10 @@ void cLuaState::Create(void) luaL_openlibs(m_LuaState); m_IsOwned = true; cLuaStateTracker::Add(*this); + + // Add the CanonLuaState value into the Lua state, so that we can get it from anywhere: + lua_pushlightuserdata(m_LuaState, reinterpret_cast(this)); + lua_setglobal(m_LuaState, g_CanonLuaStateGlobalName); } @@ -206,6 +284,16 @@ void cLuaState::Close(void) Detach(); return; } + + // Invalidate all callbacks: + { + cCSLock Lock(m_CSTrackedCallbacks); + for (auto & c: m_TrackedCallbacks) + { + c->Invalidate(); + } + } + cLuaStateTracker::Del(*this); lua_close(m_LuaState); m_LuaState = nullptr; @@ -871,6 +959,15 @@ bool cLuaState::GetStackValue(int a_StackPos, cRef & a_Ref) +bool cLuaState::GetStackValue(int a_StackPos, cCallback & a_Callback) +{ + return a_Callback.RefStack(*this, a_StackPos); +} + + + + + bool cLuaState::GetStackValue(int a_StackPos, double & a_ReturnedVal) { if (lua_isnumber(m_LuaState, a_StackPos)) @@ -1626,6 +1723,52 @@ int cLuaState::BreakIntoDebugger(lua_State * a_LuaState) +void cLuaState::TrackCallback(cCallback & a_Callback) +{ + // Get the CanonLuaState global from Lua: + auto cb = WalkToNamedGlobal(g_CanonLuaStateGlobalName); + if (!cb.IsValid()) + { + LOGWARNING("%s: Lua state %p has invalid CanonLuaState!", __FUNCTION__, reinterpret_cast(m_LuaState)); + return; + } + auto & canonState = *reinterpret_cast(lua_touserdata(m_LuaState, -1)); + + // Add the callback: + cCSLock Lock(canonState.m_CSTrackedCallbacks); + canonState.m_TrackedCallbacks.push_back(&a_Callback); +} + + + + + +void cLuaState::UntrackCallback(cCallback & a_Callback) +{ + // Get the CanonLuaState global from Lua: + auto cb = WalkToNamedGlobal(g_CanonLuaStateGlobalName); + if (!cb.IsValid()) + { + LOGWARNING("%s: Lua state %p has invalid CanonLuaState!", __FUNCTION__, reinterpret_cast(m_LuaState)); + return; + } + auto & canonState = *reinterpret_cast(lua_touserdata(m_LuaState, -1)); + + // Remove the callback: + cCSLock Lock(canonState.m_CSTrackedCallbacks); + auto & trackedCallbacks = canonState.m_TrackedCallbacks; + trackedCallbacks.erase(std::remove_if(trackedCallbacks.begin(), trackedCallbacks.end(), + [&a_Callback](cCallback * a_StoredCallback) + { + return (a_StoredCallback == &a_Callback); + } + )); +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cLuaState::cRef: @@ -1681,7 +1824,7 @@ void cLuaState::cRef::RefStack(cLuaState & a_LuaState, int a_StackPos) { UnRef(); } - m_LuaState = &a_LuaState; + m_LuaState = a_LuaState; lua_pushvalue(a_LuaState, a_StackPos); // Push a copy of the value at a_StackPos onto the stack m_Ref = luaL_ref(a_LuaState, LUA_REGISTRYINDEX); } @@ -1692,11 +1835,9 @@ void cLuaState::cRef::RefStack(cLuaState & a_LuaState, int a_StackPos) void cLuaState::cRef::UnRef(void) { - ASSERT(m_LuaState->IsValid()); // The reference should be destroyed before destroying the LuaState - if (IsValid()) { - luaL_unref(*m_LuaState, LUA_REGISTRYINDEX, m_Ref); + luaL_unref(m_LuaState, LUA_REGISTRYINDEX, m_Ref); } m_LuaState = nullptr; m_Ref = LUA_REFNIL; -- cgit v1.2.3 From eb044e140e593c037976bacd56c5a50f133d3ba2 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 2 Mar 2016 10:12:43 +0100 Subject: Changed plugin hook registrations to use cLuaState::cCallback. --- src/Bindings/LuaState.cpp | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) (limited to 'src/Bindings/LuaState.cpp') diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 8e4f48275..91a9ef4d6 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -170,6 +170,16 @@ void cLuaState::cCallback::Clear(void) +bool cLuaState::cCallback::IsValid(void) +{ + cCSLock lock(m_CS); + return m_Ref.IsValid(); +} + + + + + void cLuaState::cCallback::Invalidate(void) { cCSLock Lock(m_CS); @@ -935,6 +945,24 @@ bool cLuaState::GetStackValue(int a_StackPos, bool & a_ReturnedVal) +bool cLuaState::GetStackValue(int a_StackPos, cCallback & a_Callback) +{ + return a_Callback.RefStack(*this, a_StackPos); +} + + + + + +bool cLuaState::GetStackValue(int a_StackPos, cCallbackPtr & a_Callback) +{ + return a_Callback->RefStack(*this, a_StackPos); +} + + + + + bool cLuaState::GetStackValue(int a_StackPos, cPluginManager::CommandResult & a_Result) { if (lua_isnumber(m_LuaState, a_StackPos)) @@ -959,15 +987,6 @@ bool cLuaState::GetStackValue(int a_StackPos, cRef & a_Ref) -bool cLuaState::GetStackValue(int a_StackPos, cCallback & a_Callback) -{ - return a_Callback.RefStack(*this, a_StackPos); -} - - - - - bool cLuaState::GetStackValue(int a_StackPos, double & a_ReturnedVal) { if (lua_isnumber(m_LuaState, a_StackPos)) -- cgit v1.2.3 From af200dfaae63e61bf0bbd237582e3cbbe08baed6 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 16 Mar 2016 10:58:28 +0100 Subject: Changed cLuaWindow callbacks to use cLuaState::cCallback. --- src/Bindings/LuaState.cpp | 72 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 14 deletions(-) (limited to 'src/Bindings/LuaState.cpp') diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 91a9ef4d6..98507e96c 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -180,6 +180,25 @@ bool cLuaState::cCallback::IsValid(void) +bool cLuaState::cCallback::IsSameLuaState(cLuaState & a_LuaState) +{ + cCSLock lock(m_CS); + if (!m_Ref.IsValid()) + { + return false; + } + auto canonState = a_LuaState.QueryCanonLuaState(); + if (canonState == nullptr) + { + return false; + } + return (m_Ref.GetLuaState() == static_cast(*canonState)); +} + + + + + void cLuaState::cCallback::Invalidate(void) { cCSLock Lock(m_CS); @@ -919,6 +938,18 @@ void cLuaState::Push(std::chrono::milliseconds a_Value) +void cLuaState::Pop(int a_NumValuesToPop) +{ + ASSERT(IsValid()); + + lua_pop(m_LuaState, a_NumValuesToPop); + m_NumCurrentFunctionArgs -= a_NumValuesToPop; +} + + + + + bool cLuaState::GetStackValue(int a_StackPos, AString & a_Value) { size_t len = 0; @@ -1647,7 +1678,7 @@ int cLuaState::CopyStackFrom(cLuaState & a_SrcLuaState, int a_SrcStart, int a_Sr LOGWARNING("%s: Unsupported value: '%s' at stack position %d. Can only copy numbers, strings, bools and classes!", __FUNCTION__, lua_typename(a_SrcLuaState, t), i ); - a_SrcLuaState.LogStack("Stack where copying failed:"); + a_SrcLuaState.LogStackValues("Stack where copying failed:"); lua_pop(m_LuaState, i - a_SrcStart); return -1; } @@ -1674,16 +1705,16 @@ void cLuaState::ToString(int a_StackPos, AString & a_String) -void cLuaState::LogStack(const char * a_Header) +void cLuaState::LogStackValues(const char * a_Header) { - LogStack(m_LuaState, a_Header); + LogStackValues(m_LuaState, a_Header); } -void cLuaState::LogStack(lua_State * a_LuaState, const char * a_Header) +void cLuaState::LogStackValues(lua_State * a_LuaState, const char * a_Header) { // Format string consisting only of %s is used to appease the compiler LOG("%s", (a_Header != nullptr) ? a_Header : "Lua C API Stack contents:"); @@ -1708,6 +1739,21 @@ void cLuaState::LogStack(lua_State * a_LuaState, const char * a_Header) +cLuaState * cLuaState::QueryCanonLuaState(void) +{ + // Get the CanonLuaState global from Lua: + auto cb = WalkToNamedGlobal(g_CanonLuaStateGlobalName); + if (!cb.IsValid()) + { + return nullptr; + } + return reinterpret_cast(lua_touserdata(m_LuaState, -1)); +} + + + + + int cLuaState::ReportFnCallErrors(lua_State * a_LuaState) { LOGWARNING("LUA: %s", lua_tostring(a_LuaState, -1)); @@ -1745,17 +1791,16 @@ int cLuaState::BreakIntoDebugger(lua_State * a_LuaState) void cLuaState::TrackCallback(cCallback & a_Callback) { // Get the CanonLuaState global from Lua: - auto cb = WalkToNamedGlobal(g_CanonLuaStateGlobalName); - if (!cb.IsValid()) + auto canonState = QueryCanonLuaState(); + if (canonState == nullptr) { LOGWARNING("%s: Lua state %p has invalid CanonLuaState!", __FUNCTION__, reinterpret_cast(m_LuaState)); return; } - auto & canonState = *reinterpret_cast(lua_touserdata(m_LuaState, -1)); // Add the callback: - cCSLock Lock(canonState.m_CSTrackedCallbacks); - canonState.m_TrackedCallbacks.push_back(&a_Callback); + cCSLock Lock(canonState->m_CSTrackedCallbacks); + canonState->m_TrackedCallbacks.push_back(&a_Callback); } @@ -1765,17 +1810,16 @@ void cLuaState::TrackCallback(cCallback & a_Callback) void cLuaState::UntrackCallback(cCallback & a_Callback) { // Get the CanonLuaState global from Lua: - auto cb = WalkToNamedGlobal(g_CanonLuaStateGlobalName); - if (!cb.IsValid()) + auto canonState = QueryCanonLuaState(); + if (canonState == nullptr) { LOGWARNING("%s: Lua state %p has invalid CanonLuaState!", __FUNCTION__, reinterpret_cast(m_LuaState)); return; } - auto & canonState = *reinterpret_cast(lua_touserdata(m_LuaState, -1)); // Remove the callback: - cCSLock Lock(canonState.m_CSTrackedCallbacks); - auto & trackedCallbacks = canonState.m_TrackedCallbacks; + cCSLock Lock(canonState->m_CSTrackedCallbacks); + auto & trackedCallbacks = canonState->m_TrackedCallbacks; trackedCallbacks.erase(std::remove_if(trackedCallbacks.begin(), trackedCallbacks.end(), [&a_Callback](cCallback * a_StoredCallback) { -- cgit v1.2.3