From 1f75d4522210c4774f3de34ddea084cfa764e9e3 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 f11e74e75..ffe1fe4ac 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)) @@ -1701,6 +1798,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: @@ -1756,7 +1899,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); } @@ -1767,11 +1910,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 4489a89fdec9f4a507400150af34623899b64f46 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 ffe1fe4ac..28274d681 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 fb4c3fc4d9325c28b8640f0e717e5e320334a7c6 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Fri, 10 Jun 2016 21:30:07 +0200 Subject: Changed cLuaWindow callbacks to use cLuaState::cCallback. --- src/Bindings/LuaState.cpp | 70 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 13 deletions(-) (limited to 'src/Bindings/LuaState.cpp') diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 28274d681..550737704 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; @@ -1748,16 +1779,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:"); @@ -1783,6 +1814,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)); @@ -1820,17 +1866,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); } @@ -1840,17 +1885,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 From 24853397ef4648155d886b112e00c3e2c3d1e900 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Sun, 12 Jun 2016 16:53:24 +0200 Subject: LuaState: Implemented proper locking for cCallback. --- src/Bindings/LuaState.cpp | 58 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 12 deletions(-) (limited to 'src/Bindings/LuaState.cpp') diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 550737704..85c6c2e12 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -124,6 +124,15 @@ cLuaStateTracker & cLuaStateTracker::Get(void) //////////////////////////////////////////////////////////////////////////////// // cLuaState::cCallback: +cLuaState::cCallback::cCallback(void): + m_CS(nullptr) +{ +} + + + + + bool cLuaState::cCallback::RefStack(cLuaState & a_LuaState, int a_StackPos) { // Check if the stack contains a function: @@ -136,11 +145,12 @@ bool cLuaState::cCallback::RefStack(cLuaState & a_LuaState, int a_StackPos) Clear(); // Add self to LuaState's callback-tracking: - a_LuaState.TrackCallback(*this); + auto canonState = a_LuaState.QueryCanonLuaState(); + canonState->TrackCallback(*this); // Store the new callback: - cCSLock Lock(m_CS); - m_Ref.RefStack(a_LuaState, a_StackPos); + m_CS = &(canonState->m_CS); + m_Ref.RefStack(*canonState, a_StackPos); return true; } @@ -153,16 +163,24 @@ void cLuaState::cCallback::Clear(void) // Free the callback reference: lua_State * luaState = nullptr; { - cCSLock Lock(m_CS); - if (!m_Ref.IsValid()) + auto cs = m_CS; + 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: + if (luaState == nullptr) + { + return; + } cLuaState(luaState).UntrackCallback(*this); } @@ -172,7 +190,12 @@ void cLuaState::cCallback::Clear(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(); } @@ -182,7 +205,12 @@ bool cLuaState::cCallback::IsValid(void) 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()) { return false; @@ -201,10 +229,16 @@ bool cLuaState::cCallback::IsSameLuaState(cLuaState & a_LuaState) 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()) { - 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(this) ); return; -- cgit v1.2.3 From 257c5a1a54396a3610f63bf469d6cf50ec76aef5 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Sun, 12 Jun 2016 18:11:40 +0200 Subject: cPluginManager: Use a callback for command handler registration. --- src/Bindings/LuaState.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/Bindings/LuaState.cpp') diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 85c6c2e12..0d958cc20 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -1021,6 +1021,10 @@ bool cLuaState::GetStackValue(int a_StackPos, cCallback & a_Callback) bool cLuaState::GetStackValue(int a_StackPos, cCallbackPtr & a_Callback) { + if (a_Callback == nullptr) + { + a_Callback = std::make_shared(); + } return a_Callback->RefStack(*this, a_StackPos); } -- cgit v1.2.3 From 7a6670d1d110be96ed73ccab4f33c69e4a01f28d Mon Sep 17 00:00:00 2001 From: Mattes D Date: Sun, 12 Jun 2016 18:24:01 +0200 Subject: Removed dead code related to callbacks. --- src/Bindings/LuaState.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Bindings/LuaState.cpp') diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 0d958cc20..109809cab 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -553,7 +553,7 @@ bool cLuaState::PushFunction(const char * a_FunctionName) -bool cLuaState::PushFunction(int a_FnRef) +bool cLuaState::PushFunction(const cRef & a_FnRef) { ASSERT(IsValid()); ASSERT(m_NumCurrentFunctionArgs == -1); // If not, there's already something pushed onto the stack @@ -561,7 +561,7 @@ bool cLuaState::PushFunction(int a_FnRef) // Push the error handler for lua_pcall() lua_pushcfunction(m_LuaState, &ReportFnCallErrors); - lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_FnRef); // same as lua_getref() + lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, static_cast(a_FnRef)); // same as lua_getref() if (!lua_isfunction(m_LuaState, -1)) { lua_pop(m_LuaState, 2); -- cgit v1.2.3 From bf88312a1664311968736b4ba7ce1458c8b0954e Mon Sep 17 00:00:00 2001 From: Mattes D Date: Mon, 27 Jun 2016 20:49:59 +0200 Subject: Converted cLuaState::cCallbackPtr into a UniquePtr. --- src/Bindings/LuaState.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src/Bindings/LuaState.cpp') diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 109809cab..5e6c24365 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -1020,6 +1020,19 @@ bool cLuaState::GetStackValue(int a_StackPos, cCallback & a_Callback) bool cLuaState::GetStackValue(int a_StackPos, cCallbackPtr & a_Callback) +{ + if (a_Callback == nullptr) + { + a_Callback = cpp14::make_unique(); + } + return a_Callback->RefStack(*this, a_StackPos); +} + + + + + +bool cLuaState::GetStackValue(int a_StackPos, cCallbackSharedPtr & a_Callback) { if (a_Callback == nullptr) { -- cgit v1.2.3