1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
/*
* 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 "SectionLoader.h"
#include "cores/DllLoader/DllLoaderContainer.h"
#include "utils/GlobalsHandling.h"
#include "utils/StringUtils.h"
#include "utils/log.h"
#include <mutex>
#define g_sectionLoader XBMC_GLOBAL_USE(CSectionLoader)
// delay for unloading dll's
#define UNLOAD_DELAY 30*1000 // 30 sec.
//Define this to get logging on all calls to load/unload sections/dlls
//#define LOGALL
CSectionLoader::CSectionLoader(void) = default;
CSectionLoader::~CSectionLoader(void)
{
UnloadAll();
}
LibraryLoader *CSectionLoader::LoadDLL(const std::string &dllname, bool bDelayUnload /*=true*/, bool bLoadSymbols /*=false*/)
{
std::unique_lock<CCriticalSection> lock(g_sectionLoader.m_critSection);
if (dllname.empty()) return NULL;
// check if it's already loaded, and increase the reference count if so
for (int i = 0; i < (int)g_sectionLoader.m_vecLoadedDLLs.size(); ++i)
{
CDll& dll = g_sectionLoader.m_vecLoadedDLLs[i];
if (StringUtils::EqualsNoCase(dll.m_strDllName, dllname))
{
dll.m_lReferenceCount++;
return dll.m_pDll;
}
}
// ok, now load the dll
CLog::Log(LOGDEBUG, "SECTION:LoadDLL({})", dllname);
LibraryLoader* pDll = DllLoaderContainer::LoadModule(dllname.c_str(), NULL, bLoadSymbols);
if (!pDll)
return NULL;
CDll newDLL;
newDLL.m_strDllName = dllname;
newDLL.m_lReferenceCount = 1;
newDLL.m_bDelayUnload=bDelayUnload;
newDLL.m_pDll=pDll;
g_sectionLoader.m_vecLoadedDLLs.push_back(newDLL);
return newDLL.m_pDll;
}
void CSectionLoader::UnloadDLL(const std::string &dllname)
{
std::unique_lock<CCriticalSection> lock(g_sectionLoader.m_critSection);
if (dllname.empty()) return;
// check if it's already loaded, and decrease the reference count if so
for (int i = 0; i < (int)g_sectionLoader.m_vecLoadedDLLs.size(); ++i)
{
CDll& dll = g_sectionLoader.m_vecLoadedDLLs[i];
if (StringUtils::EqualsNoCase(dll.m_strDllName, dllname))
{
dll.m_lReferenceCount--;
if (0 == dll.m_lReferenceCount)
{
if (dll.m_bDelayUnload)
dll.m_unloadDelayStartTick = std::chrono::steady_clock::now();
else
{
CLog::Log(LOGDEBUG, "SECTION:UnloadDll({})", dllname);
if (dll.m_pDll)
DllLoaderContainer::ReleaseModule(dll.m_pDll);
g_sectionLoader.m_vecLoadedDLLs.erase(g_sectionLoader.m_vecLoadedDLLs.begin() + i);
}
return;
}
}
}
}
void CSectionLoader::UnloadDelayed()
{
std::unique_lock<CCriticalSection> lock(g_sectionLoader.m_critSection);
// check if we can unload any unreferenced dlls
for (int i = 0; i < (int)g_sectionLoader.m_vecLoadedDLLs.size(); ++i)
{
CDll& dll = g_sectionLoader.m_vecLoadedDLLs[i];
auto now = std::chrono::steady_clock::now();
auto duration =
std::chrono::duration_cast<std::chrono::milliseconds>(now - dll.m_unloadDelayStartTick);
if (dll.m_lReferenceCount == 0 && duration.count() > UNLOAD_DELAY)
{
CLog::Log(LOGDEBUG, "SECTION:UnloadDelayed(DLL: {})", dll.m_strDllName);
if (dll.m_pDll)
DllLoaderContainer::ReleaseModule(dll.m_pDll);
g_sectionLoader.m_vecLoadedDLLs.erase(g_sectionLoader.m_vecLoadedDLLs.begin() + i);
return;
}
}
}
void CSectionLoader::UnloadAll()
{
// delete the dll's
std::unique_lock<CCriticalSection> lock(g_sectionLoader.m_critSection);
std::vector<CDll>::iterator it = g_sectionLoader.m_vecLoadedDLLs.begin();
while (it != g_sectionLoader.m_vecLoadedDLLs.end())
{
CDll& dll = *it;
if (dll.m_pDll)
DllLoaderContainer::ReleaseModule(dll.m_pDll);
it = g_sectionLoader.m_vecLoadedDLLs.erase(it);
}
}
|