diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
commit | c04dcc2e7d834218ef2d4194331e383402495ae1 (patch) | |
tree | 7333e38d10d75386e60f336b80c2443c1166031d /xbmc/interfaces/legacy/CallbackHandler.cpp | |
parent | Initial commit. (diff) | |
download | kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip |
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/interfaces/legacy/CallbackHandler.cpp')
-rw-r--r-- | xbmc/interfaces/legacy/CallbackHandler.cpp | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/xbmc/interfaces/legacy/CallbackHandler.cpp b/xbmc/interfaces/legacy/CallbackHandler.cpp new file mode 100644 index 0000000..f567168 --- /dev/null +++ b/xbmc/interfaces/legacy/CallbackHandler.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "CallbackHandler.h" + +#include "AddonUtils.h" +#include "commons/Exception.h" +#include "utils/log.h" + +#include <mutex> +#include <vector> + +namespace XBMCAddon +{ + class AsyncCallbackMessage : public AddonClass + { + public: + AddonClass::Ref<Callback> cb; + AddonClass::Ref<RetardedAsyncCallbackHandler> handler; + AsyncCallbackMessage(Callback* _cb, RetardedAsyncCallbackHandler* _handler) : + cb(_cb), handler(_handler) { XBMC_TRACE; } + }; + + //******************************************************************** + // This holds the callback messages which will be executed. It doesn't + // seem to work correctly with the Ref object so we'll go with Ref*'s + typedef std::vector<AddonClass::Ref<AsyncCallbackMessage> > CallbackQueue; + //******************************************************************** + + static CCriticalSection critSection; + static CallbackQueue g_callQueue; + + void RetardedAsyncCallbackHandler::invokeCallback(Callback* cb) + { + XBMC_TRACE; + std::unique_lock<CCriticalSection> lock(critSection); + g_callQueue.push_back(new AsyncCallbackMessage(cb,this)); + } + + RetardedAsyncCallbackHandler::~RetardedAsyncCallbackHandler() + { + XBMC_TRACE; + std::unique_lock<CCriticalSection> lock(critSection); + + // find any messages that might be there because of me ... and remove them + CallbackQueue::iterator iter = g_callQueue.begin(); + while (iter != g_callQueue.end()) + { + if ((*iter)->handler.get() == this) // then this message is because of me + { + g_callQueue.erase(iter); + iter = g_callQueue.begin(); + } + else + ++iter; + } + } + + void RetardedAsyncCallbackHandler::makePendingCalls() + { + XBMC_TRACE; + std::unique_lock<CCriticalSection> lock(critSection); + CallbackQueue::iterator iter = g_callQueue.begin(); + while (iter != g_callQueue.end()) + { + AddonClass::Ref<AsyncCallbackMessage> p(*iter); + + // only call when we are in the right thread state + if(p->handler->isStateOk(p->cb->getObject())) + { + // remove it from the queue. No matter what we're done with + // this. Even if it doesn't execute for some reason. + g_callQueue.erase(iter); + + // we need to release the critSection lock prior to grabbing the + // lock on the object. Not doing so results in deadlocks. We no + // longer are accessing the g_callQueue so it's fine to do this now + { + XBMCAddonUtils::InvertSingleLockGuard unlock(lock); + + // make sure the object is not deallocating + + // we need to grab the object lock to see if the object of the call + // is deallocating. holding this lock should prevent it from + // deallocating during the execution of this call. +#ifdef ENABLE_XBMC_TRACE_API + CLog::Log(LOGDEBUG, "{}NEWADDON executing callback 0x{:x}", _tg.getSpaces(), + (long)(p->cb.get())); +#endif + AddonClass* obj = (p->cb->getObject()); + AddonClass::Ref<AddonClass> ref(obj); + std::unique_lock<CCriticalSection> lock2(*obj); + if (!p->cb->getObject()->isDeallocating()) + { + try + { + // need to make the call + p->cb->executeCallback(); + } + catch (XbmcCommons::Exception& e) { e.LogThrowMessage(); } + catch (...) + { + CLog::Log(LOGERROR, "Unknown exception while executing callback {:#x}", + reinterpret_cast<int64_t>(p->cb.get())); + } + } + } + + // since the state of the iterator may have been corrupted by + // the changing state of the list from another thread during + // the releasing fo the lock in the immediately preceeding + // codeblock, we need to reset it before continuing the loop + iter = g_callQueue.begin(); + } + else // if we're not in the right thread for this callback... + ++iter; + } + } + + void RetardedAsyncCallbackHandler::clearPendingCalls(void* userData) + { + XBMC_TRACE; + std::unique_lock<CCriticalSection> lock(critSection); + CallbackQueue::iterator iter = g_callQueue.begin(); + while (iter != g_callQueue.end()) + { + AddonClass::Ref<AsyncCallbackMessage> p(*iter); + + if(p->handler->shouldRemoveCallback(p->cb->getObject(),userData)) + { +#ifdef ENABLE_XBMC_TRACE_API + CLog::Log(LOGDEBUG, + "{}NEWADDON removing callback 0x{:x} for PyThreadState 0x{:x} from queue", + _tg.getSpaces(), (long)(p->cb.get()), (long)userData); +#endif + iter = g_callQueue.erase(iter); + } + else + ++iter; + } + } +} + |