#include #include #include #include #include #include "tactility/driver.h" #include constexpr auto* TAG = "module"; struct ModuleInternal { bool started = false; bool drivers_ready = false; }; struct ModuleLedger { std::vector modules; Mutex mutex {}; ModuleLedger() { mutex_construct(&mutex); } ~ModuleLedger() { mutex_destruct(&mutex); } }; static ModuleLedger ledger; extern "C" { error_t module_construct(Module* module) { module->internal = new (std::nothrow) ModuleInternal(); if (module->internal == nullptr) return ERROR_OUT_OF_MEMORY; return ERROR_NONE; } error_t module_destruct(Module* module) { delete static_cast(module->internal); module->internal = nullptr; return ERROR_NONE; } error_t module_add(Module* module) { mutex_lock(&ledger.mutex); ledger.modules.push_back(module); mutex_unlock(&ledger.mutex); return ERROR_NONE; } error_t module_remove(Module* module) { mutex_lock(&ledger.mutex); ledger.modules.erase(std::remove(ledger.modules.begin(), ledger.modules.end(), module), ledger.modules.end()); mutex_unlock(&ledger.mutex); return ERROR_NONE; } error_t module_start(Module* module) { LOG_I(TAG, "start %s", module->name); auto* internal = module->internal; if (internal == nullptr) return ERROR_INVALID_STATE; if (internal->started) return ERROR_NONE; if (module->start != nullptr) { auto error = module->start(); if (error != ERROR_NONE) { return error; } } if (module->drivers != nullptr && !internal->drivers_ready) { auto* driver_location = module->drivers; while (*driver_location != nullptr) { auto driver = *driver_location; check(driver_construct_add(driver) == ERROR_NONE); driver_location++; } internal->drivers_ready = true; } internal->started = true; return ERROR_NONE; } bool module_is_started(Module* module) { auto* internal = module->internal; return internal != nullptr && internal->started; } error_t module_stop(Module* module) { LOG_I(TAG, "stop %s", module->name); auto* internal = module->internal; if (internal == nullptr) return ERROR_INVALID_STATE; if (!internal->started) return ERROR_NONE; if (module->drivers != nullptr && internal->drivers_ready) { size_t count = 0; while (module->drivers[count] != nullptr) { count++; } for (size_t i = count; i-- > 0;) { check(driver_remove_destruct(module->drivers[i]) == ERROR_NONE); } internal->drivers_ready = false; } if (module->stop != nullptr) { auto error = module->stop(); if (error != ERROR_NONE) { return error; } } internal->started = false; return ERROR_NONE; } error_t module_construct_add_start(Module* module) { error_t error = module_construct(module); if (error != ERROR_NONE) return error; error = module_add(module); if (error != ERROR_NONE) return error; return module_start(module); } bool module_resolve_symbol(Module* module, const char* symbol_name, uintptr_t* symbol_address) { if (!module_is_started(module)) return false; auto* symbol_ptr = module->symbols; if (symbol_ptr == nullptr) return false; while (symbol_ptr->name != nullptr) { if (strcmp(symbol_ptr->name, symbol_name) == 0) { *symbol_address = reinterpret_cast(symbol_ptr->symbol); return true; } symbol_ptr++; } return false; } bool module_resolve_symbol_global(const char* symbol_name, uintptr_t* symbol_address) { mutex_lock(&ledger.mutex); for (auto* module : ledger.modules) { if (!module_is_started(module)) continue; if (module_resolve_symbol(module, symbol_name, symbol_address)) { mutex_unlock(&ledger.mutex); return true; } } mutex_unlock(&ledger.mutex); return false; } }