Skip to content

Commit ad60aa5

Browse files
add minimal plugin system
1 parent 34d1f72 commit ad60aa5

9 files changed

Lines changed: 173 additions & 0 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,9 @@
3333

3434
# Directories
3535
build/
36+
37+
# IDEs and LSP specific
3638
.vscode/
3739
__pycache__/
40+
.cache/
41+
compile_commands.json

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ include(cmake/defaults.cmake)
88

99
add_subdirectory(third_party)
1010
add_subdirectory(scripts)
11+
add_subdirectory(plugins)
1112

1213
set(hSIM_LIB
1314
src/memory.cc src/machine.cc

include/machine.hh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
#define HSIM_MACHINE_INCLUDED
33

44
#include <memory>
5+
#include <string>
56

67
#include "config.hh"
78
#include "cpu_state.hh"
89
#include "elf_loader.hh"
910
#include "executors.hh"
1011
#include "memory.hh"
12+
#include "plugin_manager.hh"
1113

1214
namespace hsim {
1315

@@ -32,9 +34,14 @@ class Machine final {
3234
}
3335
}
3436

37+
void loadPlugin(const std::string& pluginPath, const std::string& options = "") {
38+
m_plugins.loadPlugin(pluginPath, options);
39+
}
40+
3541
private:
3642
std::unique_ptr<CpuState> m_state;
3743
Memory m_mem{};
44+
PluginManager m_plugins;
3845
};
3946

4047
} // namespace hsim

include/plugin.hh

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#ifndef HSIM_PLUGIN_INCLUDED
2+
#define HSIM_PLUGIN_INCLUDED
3+
4+
#include <stdexcept>
5+
#include <string>
6+
7+
#include <dlfcn.h>
8+
9+
#include "plugin_api.hh"
10+
11+
namespace hsim {
12+
13+
class Plugin final {
14+
public:
15+
Plugin(const std::string &pluginPath, const std::string &options = "")
16+
: m_pluginName{pluginPath}, m_options{options} {
17+
m_dlhandle = dlopen(pluginPath.c_str(), RTLD_NOW);
18+
if (m_dlhandle == nullptr) {
19+
std::string dlErrorMsg = dlerror();
20+
std::string fullErrorMsg = "Unable to load plugin: " + pluginPath +
21+
". Error: " + dlErrorMsg;
22+
throw std::runtime_error(fullErrorMsg);
23+
}
24+
25+
auto loadFunc = reinterpret_cast<LoadFunc>(
26+
dlsym(m_dlhandle, kLoadFuncName.c_str()));
27+
if (loadFunc == nullptr) {
28+
std::string dlErrorMsg = dlerror();
29+
std::string fullErrorMsg =
30+
"Unable to load : " + pluginPath + ". Error: " + dlErrorMsg;
31+
throw std::runtime_error(fullErrorMsg);
32+
}
33+
34+
LoadablePlugin plugin = loadFunc(options.c_str());
35+
m_pluginMem = plugin.pluginMem;
36+
m_notify = plugin.notify;
37+
m_unload = plugin.unload;
38+
}
39+
40+
~Plugin() {
41+
m_unload(m_pluginMem);
42+
43+
dlclose(m_dlhandle);
44+
}
45+
46+
void notify() { m_notify(m_pluginMem); }
47+
48+
private:
49+
std::string m_pluginName;
50+
std::string m_options;
51+
52+
void *m_dlhandle;
53+
void *m_pluginMem;
54+
NotifyFunc m_notify;
55+
UnloadFunc m_unload;
56+
};
57+
58+
} // namespace hsim
59+
60+
#endif // HSIM_PLUGIN_INCLUDED

include/plugin_api.hh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#ifndef HSIM_PLUGIN_API_INCLUDED
2+
#define HSIM_PLUGIN_API_INCLUDED
3+
4+
#include <string>
5+
6+
#define PLUGIN_API_ATTR extern "C"
7+
8+
namespace hsim {
9+
10+
static const std::string kLoadFuncName = "loadPlugin";
11+
12+
struct LoadablePlugin;
13+
14+
extern "C" {
15+
16+
using LoadFunc = LoadablePlugin (*)(const char *options);
17+
using NotifyFunc = void (*)(void *pluginMem);
18+
using UnloadFunc = void (*)(void *pluginMem);
19+
20+
} // extern "C"
21+
22+
struct LoadablePlugin {
23+
void *pluginMem;
24+
NotifyFunc notify;
25+
UnloadFunc unload;
26+
};
27+
28+
}; // namespace hsim
29+
30+
#endif // HSIM_PLUGIN_API_INCLUDED

include/plugin_manager.hh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#ifndef HSIM_PLUGIN_MANAGER_INCLUDED
2+
#define HSIM_PLUGIN_MANAGER_INCLUDED
3+
4+
#include <string>
5+
#include <vector>
6+
7+
#include "plugin.hh"
8+
9+
namespace hsim {
10+
11+
class PluginManager final {
12+
public:
13+
void loadPlugin(const std::string &pluginPath,
14+
const std::string &options = "") {
15+
m_plugins.emplace_back(pluginPath, options);
16+
}
17+
18+
void notify() {
19+
for (auto &plugin : m_plugins) {
20+
plugin.notify();
21+
}
22+
}
23+
24+
private:
25+
std::vector<Plugin> m_plugins;
26+
};
27+
28+
} // namespace hsim
29+
30+
#endif // HSIM_PLUGIN_MANAGER_INCLUDED

plugins/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
include_directories(
2+
${CMAKE_SOURCE_DIR}/include
3+
)
4+
5+
set(PLUGIN_OUTPUT_DIR "${CMAKE_BINARY_DIR}/plugins")
6+
file(MAKE_DIRECTORY ${PLUGIN_OUTPUT_DIR})
7+
8+
add_library(simple_plugin SHARED
9+
simple_plugin.cc
10+
)
11+
12+
set_target_properties(simple_plugin PROPERTIES
13+
LIBRARY_OUTPUT_DIRECTORY ${PLUGIN_OUTPUT_DIR}
14+
)

plugins/simple_plugin.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include "plugin_api.hh"
2+
3+
#include <iostream>
4+
5+
void notify(void* pluginMem);
6+
void unload(void* pluginMem);
7+
8+
PLUGIN_API_ATTR hsim::LoadablePlugin loadPlugin([[maybe_unused]] const char* options) {
9+
hsim::LoadablePlugin plugin = {};
10+
plugin.pluginMem = nullptr;
11+
plugin.notify = notify;
12+
plugin.unload = unload;
13+
14+
std::cout << "load plugin" << std::endl;
15+
16+
return plugin;
17+
}
18+
19+
void notify([[maybe_unused]] void* pluginMem) {
20+
std::cout << "notify plugin" << std::endl;
21+
}
22+
23+
void unload([[maybe_unused]] void* pluginMem) {
24+
std::cout << "unload plugin" << std::endl;
25+
}

src/main.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ int main(int argc, char **argv) try {
3030
//
3131
hsim::Machine machine{config};
3232

33+
// machine.loadPlugin("./build/plugins/libsimple_plugin.so");
34+
3335
machine.run();
3436

3537
return 0;

0 commit comments

Comments
 (0)