Skip to content

Commit

Permalink
add module manager (#420)
Browse files Browse the repository at this point in the history
  • Loading branch information
T-rvw authored Nov 13, 2023
1 parent e7eb397 commit 249ff6b
Show file tree
Hide file tree
Showing 8 changed files with 347 additions and 1 deletion.
19 changes: 19 additions & 0 deletions Engine/Source/Runtime/Core/Modules/IModule.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

namespace engine
{

// After loading a dll, we need to call an Init function to create inherited IModule object.
// So there is a rule about this Init function's name and ABI declaration.
static constexpr const char* ModuleInitFunctioName = "InitializeModule";
using ModuleInitFunctionPtr = void* (*)(void);

class IModule
{
public:
virtual ~IModule() {}

void Shutdown();
};

}
68 changes: 68 additions & 0 deletions Engine/Source/Runtime/Core/Modules/Module.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include "Module.h"

#include "Core/OS/DllUtils.h"
#include "Path/Path.h"

#include <cassert>

namespace engine
{

ModuleLoadResult Module::Load()
{
if (IsLoaded())
{
assert(m_handle && m_module);
return ModuleLoadResult::AlreadyLoaded;
}

bool dllFileExists = Path::FileExists(m_filePath.c_str());
if (!dllFileExists)
{
return ModuleLoadResult::FileNotExist;
}

m_handle = DllUtils::LoadDll(m_filePath.c_str());
if (!m_handle)
{
return ModuleLoadResult::LoadDllFailure;
}

auto initFunc = reinterpret_cast<ModuleInitFunctionPtr>(DllUtils::LoadDllFunction(m_handle, ModuleInitFunctioName));
if (!initFunc)
{
Unload();
return ModuleLoadResult::InterfaceMissing;
}

void* pModule = initFunc();
if (!pModule)
{
Unload();
return ModuleLoadResult::InitFailure;
}

m_module.reset(reinterpret_cast<engine::IModule*>(pModule));
m_status = ModuleStatus::Loaded;

return ModuleLoadResult::Success;
}

void Module::Unload()
{
if (m_module)
{
m_module->Shutdown();
m_module.reset(nullptr);
}

if (m_handle)
{
DllUtils::UnloadDll(m_handle);
m_handle = nullptr;
}

m_status = ModuleStatus::Unload;
}

}
82 changes: 82 additions & 0 deletions Engine/Source/Runtime/Core/Modules/Module.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#pragma once

#include "Base/Template.h"
#include "IModule.h"
#include "IO/InputArchive.hpp"
#include "IO/OutputArchive.hpp"

#include <memory>
#include <string>

namespace engine
{

enum class ModuleStatus
{
Unload,
Loaded,
};

enum class ModuleLoadResult
{
AlreadyLoaded,
FileNotExist,
LoadDllFailure,
InterfaceMissing,
InitFailure,
Success
};

class Module
{
public:
Module() = default;
Module(const Module&) = delete;
Module& operator=(const Module&) = delete;
Module(Module&&) = default;
Module& operator=(Module&&) = default;
~Module() = default;

void SetName(std::string name) { m_name = cd::MoveTemp(name); }
std::string& GetName() { return m_name; }
const std::string& GetName() const { return m_name; }

void SetFilePath(std::string path) { m_filePath = cd::MoveTemp(path); }
std::string& GetFilePath() { return m_filePath; }
const std::string& GetFilePath() const { return m_filePath; }

void SetAutoLoad(bool on) { m_autoLoad = on; }
bool& GetAutoLoad() { return m_autoLoad; }
bool GetAutoLoad() const { return m_autoLoad; }

bool IsLoaded() const { return ModuleStatus::Loaded == m_status; }
ModuleLoadResult Load();
void Unload();

template<bool SwapBytesOrder>
Module& operator<<(cd::TInputArchive<SwapBytesOrder>& inputArchive)
{
inputArchive >> GetName() >> GetFilePath() >> GetAutoLoad();
return *this;
}

template<bool SwapBytesOrder>
const Module& operator>>(cd::TOutputArchive<SwapBytesOrder>& outputArchive) const
{
outputArchive << GetName() << GetFilePath() << GetAutoLoad();
return *this;
}

private:
// Configs
std::string m_name;
std::string m_filePath;
bool m_autoLoad = false;

// Runtime
ModuleStatus m_status = ModuleStatus::Unload;
void* m_handle = nullptr;
std::unique_ptr<IModule> m_module;
};

}
73 changes: 73 additions & 0 deletions Engine/Source/Runtime/Core/Modules/ModuleManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include "ModuleManager.h"

#include "Module.h"
#include "Path/Path.h"

namespace engine
{

ModuleManager::~ModuleManager() = default;

void ModuleManager::LoadModules(bool checkAutoLoad)
{
for (auto& [_, module] : m_allModules)
{
if (!module->IsLoaded())
{
if (checkAutoLoad && module->GetAutoLoad())
{
module->Load();
}
}
}
}

void ModuleManager::UnloadModules()
{
for (auto& [_, module] : m_allModules)
{
if (module->IsLoaded())
{
module->Unload();
}
}
}

Module* ModuleManager::AddModule(const char* pFilePath)
{
std::string moduleName = Path::GetFileNameWithoutExtension(pFilePath);
StringCrc moduleCrc(moduleName);
if (auto* pModule = GetModule(moduleCrc))
{
return pModule;
}

auto module = std::make_unique<Module>();
Module* pModule = module.get();
m_allModules[moduleCrc] = cd::MoveTemp(module);

pModule->SetName(cd::MoveTemp(moduleName));
pModule->SetFilePath(pFilePath);
return pModule;
}

bool ModuleManager::FindModule(StringCrc moduleCrc) const
{
return m_allModules.find(moduleCrc) != m_allModules.end();
}

Module* ModuleManager::GetModule(StringCrc moduleCrc) const
{
auto itModule = m_allModules.find(moduleCrc);
return itModule != m_allModules.end() ? itModule->second.get() : nullptr;
}

void ModuleManager::RemoveModule(StringCrc moduleCrc)
{
if (auto itModule = m_allModules.find(moduleCrc); itModule != m_allModules.end())
{
m_allModules.erase(itModule);
}
}

}
65 changes: 65 additions & 0 deletions Engine/Source/Runtime/Core/Modules/ModuleManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#pragma once

#include "Core/StringCrc.h"
#include "IO/InputArchive.hpp"
#include "IO/OutputArchive.hpp"

#include <map>
#include <memory>
#include <string>

namespace engine
{

class Module;

class ModuleManager
{
public:
ModuleManager() = default;
ModuleManager(const ModuleManager&) = delete;
ModuleManager& operator=(const ModuleManager&) = delete;
ModuleManager(ModuleManager&&) = default;
ModuleManager& operator=(ModuleManager&&) = default;
~ModuleManager();

void LoadModules(bool checkAutoLoad = true);
void UnloadModules();

Module* AddModule(const char* pFilePath);
bool FindModule(StringCrc moduleCrc) const;
Module* GetModule(StringCrc moduleCrc) const;
void RemoveModule(StringCrc moduleCrc);

template<bool SwapBytesOrder>
ModuleManager& operator<<(cd::TInputArchive<SwapBytesOrder>& inputArchive)
{
uint32_t moduleCount;
inputArchive >> moduleCount;
for (uint32_t moduleIndex = 0U; moduleIndex < moduleCount; ++moduleIndex)
{
Module module;
inputArchive >> module;
AddModule(module.GetFilePath().c_str());
}

return *this;
}

template<bool SwapBytesOrder>
const ModuleManager& operator>>(cd::TOutputArchive<SwapBytesOrder>& outputArchive) const
{
outputArchive << static_cast<uint32_t>(m_allModules.size());
for (const auto& module : m_allModules)
{
outputArchive << module;
}

return *this;
}

private:
std::map<StringCrc, std::unique_ptr<Module>> m_allModules;
};

}
23 changes: 23 additions & 0 deletions Engine/Source/Runtime/Core/OS/DllUtils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "DllUtils.h"

#include "SDL.h"

namespace engine
{

void* DllUtils::LoadDll(const char* pFilePath)
{
return SDL_LoadObject(pFilePath);
}

void* DllUtils::LoadDllFunction(void* pHandle, const char* pFunctionName)
{
return SDL_LoadFunction(pHandle, pFunctionName);
}

void DllUtils::UnloadDll(void* pHandle)
{
return SDL_UnloadObject(pHandle);
}

}
16 changes: 16 additions & 0 deletions Engine/Source/Runtime/Core/OS/DllUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

namespace engine
{

class DllUtils
{
public:
DllUtils() = delete;

static void* LoadDll(const char* pFilePath);
static void* LoadDllFunction(void* pHandle, const char* pFunctionName);
static void UnloadDll(void* pHandle);
};

}
2 changes: 1 addition & 1 deletion Engine/Source/ThirdParty/AssetPipeline

0 comments on commit 249ff6b

Please sign in to comment.