#include "RuntimeModuleManager.h" #include #define _BSD_SOURCE // usleep() #include #include #include #include #include #include "RuntimeModule.h" #include #include #include "Globals.h" #include "Serializer.h" using namespace std; const char* state_file = "state.ser"; void RuntimeModuleManager::RegisterModule(const char* name) { RuntimeModule* module = new RuntimeModule(); module->name = name; mModules.push_back(module); } void RuntimeModuleManager::UnregisterModules() { UnloadModules(); for (int i = 0; i < mModules.size(); i++) { if (mModules[i]->handle) { mModules[i]->api.finalize(mModules[i]->state); mModules[i]->state = nullptr; dlclose(mModules[i]->handle); mModules[i]->handle = 0; mModules[i]->id = 0; delete mModules[i]; } } } void RuntimeModuleManager::LoadModule(RuntimeModule* module) { struct stat attr; bool stat_result = stat(module->name.c_str(), &attr); if (glfwGetKey(gWindow, GLFW_KEY_F11) == GLFW_PRESS) { std::cerr << "Module " << module->name << " id = " << module->id << " mtime " << ctime((time_t *) &module->mtime) << std::endl; } if ( stat_result == 0 && (module->id != attr.st_ino || module->mtime != attr.st_mtime) ) { std::cout << "Opening module " << module->name << std::endl; void *handle = dlopen(module->name.c_str(), RTLD_NOW | RTLD_GLOBAL); if (handle) { module->handle = handle; module->id = attr.st_ino; module->mtime = attr.st_mtime; module->mtimensec = attr.st_mtim.tv_nsec; const struct module_api *api = (module_api*) dlsym(module->handle, "MODULE_API"); if (api != NULL) { module->api = *api; if (module->state == NULL) { std::cout << "Initializing module " << module->name << std::endl; module->state = module->api.init(); } std::cout << "Reloading module " << module->name << std::endl; module->api.reload(module->state, gReadSerializer); } else { std::cerr << "Error: could not find API for module " << module->name << std::endl; dlclose(module->handle); module->handle = NULL; module->id = 0; } } else { std::cerr << "Error: could not load module " << module->name << std::endl; std::cerr << dlerror() << std::endl; module->handle = NULL; module->id = 0; abort(); } } } void RuntimeModuleManager::Update(float dt) { for (int i = mModules.size() - 1; i >= 0; i--) { if (mModules[i]->handle) { mModules[i]->api.step(mModules[i]->state, dt); } } } bool RuntimeModuleManager::CheckModulesChanged() { struct stat attr; for (int i = 0; i < mModules.size(); i++) { RuntimeModule* module = mModules[i]; bool stat_result = stat(module->name.c_str(), &attr); if ( stat_result == 0 && (module->id != attr.st_ino || module->mtime != attr.st_mtime) ) { return true; } } return false; } void RuntimeModuleManager::UnloadModules() { gWriteSerializer->Open(state_file); for (int i = mModules.size() - 1; i >= 0 ; i--) { if (mModules[i]->handle) { mModules[i]->api.unload(mModules[i]->state, gWriteSerializer); mModules[i]->state = nullptr; dlclose(mModules[i]->handle); mModules[i]->handle = 0; mModules[i]->id = 0; } } std::cout << "Writing state to file " << state_file << std::endl; gWriteSerializer->Close(); } void RuntimeModuleManager::LoadModules() { std::cout << "Reading state from file " << state_file << std::endl; gReadSerializer->Open(state_file); for (int i = 0; i < mModules.size(); i++) { LoadModule(mModules[i]); } gReadSerializer->Close(); }