1use crate::module::error::Error;
30use crate::module::library::types::{OsLibrary, VirtualLibrary};
31use crate::module::library::OS_EXT;
32use crate::module::loader::util::{load_by_symbol, load_lib, module_close, Dependency, DepsMap};
33use crate::module::loader::Lock;
34use crate::module::Module;
35use bp3d_debug::{debug, error};
36use std::collections::HashMap;
37use std::path::{Path, PathBuf};
38use std::sync::atomic::Ordering::SeqCst;
39use std::sync::atomic::{AtomicBool, AtomicPtr};
40use std::sync::{Mutex, MutexGuard};
41
42struct Data {
43 loader: AtomicPtr<Mutex<ModuleLoader>>,
44 is_root: AtomicBool,
45}
46
47impl Data {
48 fn install(&self, loader: ModuleLoader) -> bool {
49 let ptr = self.loader.load(SeqCst);
50 if ptr.is_null() {
51 self.loader
52 .store(Box::leak(Box::new(Mutex::new(loader))), SeqCst);
53 self.is_root.store(true, SeqCst);
54 true
55 } else {
56 false
57 }
58 }
59
60 fn install_existing(&self, loader: &'static Mutex<ModuleLoader>) -> bool {
61 let ptr = self.loader.load(SeqCst);
62 if ptr.is_null() {
63 self.is_root.store(false, SeqCst);
64 self.loader
65 .store(loader as *const Mutex<ModuleLoader> as *mut _, SeqCst);
66 true
67 } else {
68 false
69 }
70 }
71
72 fn is_root(&self) -> bool {
73 self.is_root.load(SeqCst)
74 }
75
76 fn reset(&self) {
77 self.loader.store(std::ptr::null_mut(), SeqCst);
78 self.is_root.store(false, SeqCst);
79 }
80
81 fn is_set(&self) -> bool {
82 !self.loader.load(SeqCst).is_null()
83 }
84
85 unsafe fn get(&self) -> &'static Mutex<ModuleLoader> {
87 let ptr = self.loader.load(SeqCst);
88 unsafe { &*ptr }
89 }
90}
91
92static MODULE_LOADER: Data = Data {
93 loader: AtomicPtr::new(std::ptr::null_mut()),
94 is_root: AtomicBool::new(false),
95};
96
97pub struct ModuleLoader {
99 paths: Vec<PathBuf>,
100 pub(super) modules: HashMap<usize, Module<OsLibrary>>,
101 pub(super) builtin_modules: HashMap<usize, Module<VirtualLibrary>>,
102 deps: DepsMap,
103 builtins: &'static [&'static VirtualLibrary],
104 module_name_to_id: HashMap<String, usize>,
105 last_module_id: usize,
106}
107
108impl ModuleLoader {
109 pub fn install(builtins: &'static [&'static VirtualLibrary]) {
112 debug!("Installing new ModuleLoader...");
113 let mut this = ModuleLoader {
114 paths: Default::default(),
115 modules: Default::default(),
116 deps: DepsMap::new(),
117 builtin_modules: Default::default(),
118 builtins,
119 module_name_to_id: Default::default(),
120 last_module_id: 0,
121 };
122 this._add_public_dependency(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"), ["*"]);
123 this._add_public_dependency("bp3d-debug", "1.0.0", ["*"]);
124 if !MODULE_LOADER.install(this) {
125 panic!("attempt to initialize module loader twice");
126 }
127 }
128
129 pub fn uninstall() {
132 debug!("Uninstalling ModuleLoader...");
133 if !MODULE_LOADER.is_set() {
134 panic!("attempt to uninstall a non-existent ModuleLoader");
135 }
136 if !MODULE_LOADER.is_root() {
137 MODULE_LOADER.reset()
138 } else {
139 debug!("Unloading modules...");
140 let mut loader = Self::_lock();
141 let map = loader.module_name_to_id.clone();
142 for (name, _) in map {
143 debug!("Unloading module {}...", name);
144 if let Err(e) = loader._unload(&name) {
145 error!("Failed to unload module {}: {}", name, e);
146 }
147 }
148 drop(loader);
149 debug!("Deleting ModuleLoader...");
150 unsafe {
151 drop(Box::from_raw(
152 MODULE_LOADER.get() as *const Mutex<ModuleLoader> as *mut Mutex<ModuleLoader>,
153 ));
154 }
155 MODULE_LOADER.reset();
156 }
157 }
158
159 pub(crate) fn _instance() -> &'static Mutex<ModuleLoader> {
160 unsafe { MODULE_LOADER.get() }
161 }
162
163 pub fn install_default() {
165 Self::install(&[]);
166 }
167
168 pub fn install_from_existing(loader: &'static Mutex<ModuleLoader>) {
170 if MODULE_LOADER.install_existing(loader) {
171 debug!("Installed ModuleLoader from existing instance");
172 }
173 assert_eq!(loader as *const Mutex<ModuleLoader>, unsafe {
174 MODULE_LOADER.get() as *const Mutex<ModuleLoader>
175 });
176 }
177
178 fn _lock<'a>() -> MutexGuard<'a, ModuleLoader> {
179 if !MODULE_LOADER.is_set() {
180 Self::install_default();
181 }
182 unsafe { MODULE_LOADER.get().lock().unwrap() }
183 }
184
185 fn _next_module_id(&mut self) -> usize {
186 let id = self.last_module_id;
187 self.last_module_id += 1;
188 id
189 }
190
191 pub(super) fn _get_builtin(&self, name: &str) -> Option<usize> {
192 let name = name.replace("-", "_");
193 if let Some(id) = self.module_name_to_id.get(&name) {
194 self.builtin_modules.get(id).map(|v| v.id)
195 } else {
196 None
197 }
198 }
199 pub(super) fn _get_module(&self, name: &str) -> Option<usize> {
200 let name = name.replace("-", "_");
201 if let Some(id) = self.module_name_to_id.get(&name) {
202 self.modules.get(id).map(|v| v.id)
203 } else {
204 None
205 }
206 }
207
208 pub(super) unsafe fn _load_builtin(&mut self, name: &str) -> crate::module::Result<usize> {
209 debug!("Loading builtin module: {}", name);
210 let name = name.replace("-", "_");
211 if let Some(id) = self.module_name_to_id.get(&name) {
212 match self.builtin_modules.get_mut(id) {
213 Some(v) => {
214 v.ref_count += 1;
215 Ok(*id)
216 }
217 None => Err(Error::NotFound(name)),
218 }
219 } else {
220 for builtin in self.builtins {
221 if builtin.name() == name {
222 let mut module = unsafe { load_by_symbol(**builtin, &name, &mut self.deps) }
223 .map_err(|e| match e {
224 Error::NotFound(_) => Error::MissingMetadata,
225 e => e,
226 })?;
227 let id = self._next_module_id();
228 module.id = id;
229 self.module_name_to_id.insert(name, id);
230 self.builtin_modules.entry(id).or_insert(module);
231 return Ok(id);
232 }
233 }
234 Err(Error::NotFound(name))
235 }
236 }
237
238 pub(super) unsafe fn _load_self(&mut self, name: &str) -> crate::module::Result<usize> {
239 debug!("Loading static module: {}", name);
240 let name = name.replace("-", "_");
241 if let Some(id) = self.module_name_to_id.get(&name) {
242 match self.modules.get_mut(id) {
243 Some(v) => {
244 v.ref_count += 1;
245 Ok(*id)
246 }
247 None => Err(Error::NotFound(name)),
248 }
249 } else {
250 let this = OsLibrary::open_self()?;
251 let mut module = unsafe { load_by_symbol(this, &name, &mut self.deps) }?;
252 let id = self._next_module_id();
253 module.id = id;
254 self.module_name_to_id.insert(name, id);
255 self.modules.entry(id).or_insert(module);
256 Ok(id)
257 }
258 }
259
260 pub(super) unsafe fn _load(&mut self, name: &str) -> crate::module::Result<usize> {
261 debug!("Loading dynamic module: {}", name);
262 let name = name.replace("-", "_");
263 if let Some(id) = self.module_name_to_id.get(&name) {
264 match self.modules.get_mut(id) {
265 Some(v) => {
266 v.ref_count += 1;
267 Ok(*id)
268 }
269 None => Err(Error::NotFound(name)),
270 }
271 } else {
272 let name2 = format!("{}.{}", name, OS_EXT);
273 let name3 = format!("lib{}.{}", name, OS_EXT);
274 for path in self.paths.iter() {
275 let search = path.join(&name2);
276 let search2 = path.join(&name3);
277 let mut module = None;
278 if search.exists() {
279 module = Some(load_lib(&mut self.deps, &name, &search)?);
280 } else if search2.exists() {
281 module = Some(load_lib(&mut self.deps, &name, &search2)?);
282 }
283 if let Some(mut module) = module {
284 let id = self._next_module_id();
285 module.id = id;
286 self.module_name_to_id.insert(name, id);
287 self.modules.insert(id, module);
288 return Ok(id);
289 }
290 }
291 Err(Error::NotFound(name))
292 }
293 }
294
295 pub(super) fn _unload(&mut self, name: &str) -> crate::module::Result<()> {
296 debug!("Unloading module: {}", name);
297 let name = name.replace("-", "_");
298 let id = self
299 .module_name_to_id
300 .get(&name)
301 .copied()
302 .ok_or_else(|| Error::NotFound(name.clone()))?;
303 if self.modules.contains_key(&id) {
304 let module = self.modules.get_mut(&id).unwrap();
305 module.ref_count -= 1;
306 if module.ref_count == 0 {
307 self.module_name_to_id.remove(&name);
308 let module = unsafe { self.modules.remove(&id).unwrap_unchecked() };
309 unsafe { module_close(&name, false, &module) }?;
310 drop(module);
311 }
312 } else {
313 let module = self
314 .builtin_modules
315 .get_mut(&id)
316 .ok_or_else(|| Error::NotFound(name.clone()))?;
317 module.ref_count -= 1;
318 if module.ref_count == 0 {
319 self.module_name_to_id.remove(&name);
320 let module = unsafe { self.builtin_modules.remove(&id).unwrap_unchecked() };
321 unsafe { module_close(&name, true, &module) }?;
322 drop(module);
323 }
324 }
325 Ok(())
326 }
327
328 pub(super) fn _add_search_path(&mut self, path: impl AsRef<Path>) {
329 self.paths.push(path.as_ref().into());
330 }
331
332 pub(super) fn _remove_search_path(&mut self, path: impl AsRef<Path>) {
333 self.paths.retain(|p| p != path.as_ref());
334 }
335
336 pub(super) fn _add_public_dependency<'a>(
337 &mut self,
338 name: &str,
339 version: &str,
340 features: impl IntoIterator<Item = &'a str>,
341 ) {
342 let mut negative_features = Vec::new();
343 let features = features
344 .into_iter()
345 .filter_map(|s| {
346 if s.starts_with("-") {
347 negative_features.push(s.into());
348 return None;
349 }
350 if s != "*" {
351 Some(String::from(name) + s)
352 } else {
353 Some("*".into())
354 }
355 })
356 .collect();
357 self.deps.add_dep(
358 name.replace("-", "_"),
359 Dependency {
360 version: version.into(),
361 features,
362 negative_features,
363 },
364 )
365 }
366
367 pub fn lock<'a>() -> Lock<'a> {
370 Lock {
371 lock: Self::_lock(),
372 }
373 }
374}