Actually call on_reset callback
[lsnes.git] / src / library / loadlib.cpp
blobeab9df8204a9b34356139e7ae22eb6e9a82258e4
1 #include "loadlib.hpp"
2 #include <functional>
3 #include <sstream>
4 #include <list>
5 #include <set>
7 #if defined(_WIN32) || defined(_WIN64)
8 #include <windows.h>
9 #endif
11 #if !defined(NO_DLFCN) && !defined(_WIN32) && !defined(_WIN64)
12 #include <dlfcn.h>
13 #include <unistd.h>
14 #endif
16 namespace loadlib
18 threads::lock& global_mutex()
20 static threads::lock m;
21 return m;
24 namespace
26 thread_local library* currently_loading;
27 #if defined(_WIN32) || defined(_WIN64)
28 std::string callsign = "dynamic link library";
29 std::string callsign_ext = "dll";
30 #elif !defined(NO_DLFCN)
31 #if defined(__APPLE__)
32 std::string callsign = "dynamic library";
33 std::string callsign_ext = "bundle";
34 #else
35 std::string callsign = "shared object";
36 std::string callsign_ext = "so";
37 #endif
38 #else
39 std::string callsign = "";
40 std::string callsign_ext = "";
41 #endif
44 library::internal::internal(const std::string& filename)
46 libname = filename;
47 refs = 1;
48 #if !defined(NO_DLFCN) && !defined(_WIN32) && !defined(_WIN64)
49 char buffer[16384];
50 getcwd(buffer, 16383);
51 std::string _filename = filename;
52 if(filename.find_first_of("/") >= filename.length())
53 _filename = buffer + std::string("/") + filename;
54 handle = dlopen(_filename.c_str(), RTLD_LOCAL | RTLD_NOW);
55 if(!handle)
56 throw std::runtime_error(dlerror());
57 #elif defined(_WIN32) || defined(_WIN64)
58 char buffer[16384];
59 GetCurrentDirectory(16383, buffer);
60 std::string _filename = filename;
61 if(filename.find_first_of("/\\") >= filename.length())
62 _filename = buffer + std::string("/") + filename;
63 handle = LoadLibraryA(_filename.c_str());
64 if(!handle) {
65 int errcode = GetLastError();
66 char errorbuffer[1024];
67 if(FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, errcode, 0,
68 errorbuffer, sizeof(errorbuffer), NULL))
69 throw std::runtime_error(errorbuffer);
70 else {
71 std::ostringstream str;
72 str << "Unknown system error (code " << errcode << ")";
73 throw std::runtime_error(str.str());
76 #else
77 throw std::runtime_error("Loading libraries is not supported");
78 #endif
81 library::internal::~internal() throw()
83 #if !defined(NO_DLFCN) && !defined(_WIN32) && !defined(_WIN64)
84 dlclose(handle);
85 #elif defined(_WIN32) || defined(_WIN64)
86 FreeLibrary((HMODULE)handle);
87 #endif
90 void* library::internal::operator[](const std::string& symbol) const
92 #if !defined(NO_DLFCN) && !defined(_WIN32) && !defined(_WIN64)
93 dlerror();
94 void* s = dlsym(handle, symbol.c_str());
95 if(s)
96 return s;
97 char* e = dlerror();
98 if(e)
99 throw std::runtime_error(e);
100 return NULL; //Yes, real NULL symbol.
101 #elif defined(_WIN32) || defined(_WIN64)
102 void* s = (void*)GetProcAddress((HMODULE)handle, symbol.c_str());
103 if(s)
104 return s;
105 int errcode = GetLastError();
106 char errorbuffer[1024];
107 if(FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, errcode, 0,
108 errorbuffer, sizeof(errorbuffer), NULL))
109 throw std::runtime_error(errorbuffer);
110 else {
111 std::ostringstream str;
112 str << "Unknown system error (code " << errcode << ")";
113 throw std::runtime_error(str.str());
115 #else
116 throw std::runtime_error("Library loading not supported");
117 #endif
120 const std::string& library::name() throw()
122 return callsign;
125 const std::string& library::extension() throw()
127 return callsign_ext;
130 library* library::loading() throw() { return currently_loading; }
131 void library::set_loading(library* lib) { currently_loading = lib; }
133 namespace
135 std::list<loadlib::module*>& module_queue()
137 static std::list<module*> x;
138 return x;
142 module::module(std::initializer_list<symbol> _symbols, std::function<void(const module&)> init_fn)
144 dynamic = false;
145 for(auto i : _symbols)
146 symbols[i.name] = i.address;
147 init = init_fn;
148 if(init) {
149 threads::alock h(global_mutex());
150 module_queue().push_back(this);
152 libname = "<anonymous module inside executable>";
155 module::module(library _lib)
157 dynamic = true;
158 lib = _lib;
159 libname = _lib.get_libname();
162 module::~module()
164 threads::alock h(global_mutex());
165 for(auto i = module_queue().begin(); i != module_queue().end(); i++) {
166 if(*i == this) {
167 module_queue().erase(i);
168 break;
173 module::module(const module& mod)
175 dynamic = mod.dynamic;
176 lib = mod.lib;
177 symbols = mod.symbols;
178 init = mod.init;
179 libname = mod.libname;
180 if(init) {
181 threads::alock h(global_mutex());
182 module_queue().push_back(this);
186 void* module::operator[](const std::string& symbol) const
188 if(dynamic)
189 return lib[symbol];
190 else if(symbols.count(symbol))
191 return symbols.find(symbol)->second;
192 else
193 throw std::runtime_error("Symbol '" + symbol + "' not found");
196 void module::run_initializers()
198 for(auto i : module_queue())
199 if(i->init) {
200 i->init(*i);
201 i->init = std::function<void(const module&)>();
203 module_queue().clear();