Refactored reload heuristic of modified modules

Previously I used a fixed time offset when a file change was detected.
Now I trigger a reload no module file size has changed over the last
5 updates.
master
Martin Felis 2017-02-05 10:37:49 +01:00
parent 748299c155
commit 19f3ddb901
3 changed files with 33 additions and 5 deletions

View File

@ -51,7 +51,8 @@ void RuntimeModuleManager::LoadModule(RuntimeModule* module) {
if ( stat_result == 0 && if ( stat_result == 0 &&
(module->id != attr.st_ino || module->mtime != attr.st_mtime) (module->id != attr.st_ino || module->mtime != attr.st_mtime)
) { ) {
std::cout << "Opening module " << module->name << std::endl; std::cout << "Opening module " << module->name
<< " (size = " << attr.st_size << ")" << std::endl;
void *handle = dlopen(module->name.c_str(), RTLD_NOW | RTLD_GLOBAL); void *handle = dlopen(module->name.c_str(), RTLD_NOW | RTLD_GLOBAL);
if (handle) { if (handle) {
module->handle = handle; module->handle = handle;
@ -94,16 +95,42 @@ void RuntimeModuleManager::Update(float dt) {
bool RuntimeModuleManager::CheckModulesChanged() { bool RuntimeModuleManager::CheckModulesChanged() {
struct stat attr; struct stat attr;
double current_time = gGetTimeSinceStart();
mNumUpdatesSinceLastModuleChange++;
for (int i = 0; i < mModules.size(); i++) { for (int i = 0; i < mModules.size(); i++) {
RuntimeModule* module = mModules[i]; RuntimeModule* module = mModules[i];
bool stat_result = stat(module->name.c_str(), &attr); bool stat_result = stat(module->name.c_str(), &attr);
if ( stat_result == 0 && if (stat_result != 0) {
(module->id != attr.st_ino || module->mtime != attr.st_mtime) gLog ("Error: could not stat module %s", module->name.c_str());
abort();
}
if ( module->id != attr.st_ino
|| module->mtime != attr.st_mtime
|| module->fsize != attr.st_size
|| module->fsize == 0
) { ) {
module->id = attr.st_ino;
module->mtime = attr.st_mtime;
module->mtimensec = attr.st_mtim.tv_nsec;
module->fsize = attr.st_size;
mNumUpdatesSinceLastModuleChange = 0;
gLog ("Detected file change of %s: new size %d",
module->name.c_str(), attr.st_size);
}
}
// We have to delay the actual reload trigger to make
// sure all writes to the dynamic libraries are complete.
if (mNumUpdatesSinceLastModuleChange == 5) {
gLog ("Triggering reload");
return true; return true;
} }
}
return false; return false;
} }

View File

@ -14,6 +14,7 @@ struct RuntimeModule {
void *data = nullptr; void *data = nullptr;
int mtime = 0; int mtime = 0;
int mtimensec = 0; int mtimensec = 0;
off_t fsize = 0;
struct module_api api; struct module_api api;
struct module_state *state = nullptr; struct module_state *state = nullptr;
@ -21,6 +22,7 @@ struct RuntimeModule {
struct RuntimeModuleManager { struct RuntimeModuleManager {
std::vector<RuntimeModule*> mModules; std::vector<RuntimeModule*> mModules;
int mNumUpdatesSinceLastModuleChange = 0;
void RegisterModule(const char* name); void RegisterModule(const char* name);
void UnregisterModules(); void UnregisterModules();

View File

@ -135,7 +135,6 @@ int main(void)
std::cout << "Detected module update. Unloading all modules." << std::endl; std::cout << "Detected module update. Unloading all modules." << std::endl;
module_manager.UnloadModules(); module_manager.UnloadModules();
// We need to sleep to make sure we load the new files // We need to sleep to make sure we load the new files
usleep(300000);
module_manager.LoadModules(); module_manager.LoadModules();
// We need to update our last timestamp to ignore the delay due // We need to update our last timestamp to ignore the delay due
// to reloading of the modules. // to reloading of the modules.