From b17fdca0e490d72623962f3a2c207e2c94924d88 Mon Sep 17 00:00:00 2001 From: skyjake Date: Thu, 29 Dec 2011 18:53:58 +0200 Subject: [PATCH] Unix: Refactoring plugin management (part 1) It is not possible to keep multiple game plugins in memory because of symbol clashing. Applying refactorings to allow unloading other game libraries when changing the game. --- doomsday/engine/api/dd_plugin.h | 1 + doomsday/engine/portable/include/library.h | 6 ++ doomsday/engine/portable/src/dd_main.c | 18 +++++ doomsday/engine/portable/src/library.c | 85 +++++++++++++++++++++- doomsday/plugins/jdoom/api/jdoom.def | 2 + doomsday/plugins/jdoom/src/d_api.c | 9 +++ 6 files changed, 117 insertions(+), 4 deletions(-) diff --git a/doomsday/engine/api/dd_plugin.h b/doomsday/engine/api/dd_plugin.h index e5beb880b2..08346acf68 100644 --- a/doomsday/engine/api/dd_plugin.h +++ b/doomsday/engine/api/dd_plugin.h @@ -36,6 +36,7 @@ #define MAX_HOOKS 16 #define HOOKF_EXCLUSIVE 0x01000000 +typedef int (*pluginfunc_t) (void); typedef int (*hookfunc_t) (int type, int parm, void *data); // Hook types. diff --git a/doomsday/engine/portable/include/library.h b/doomsday/engine/portable/include/library.h index 99c75014f9..1a2657d306 100644 --- a/doomsday/engine/portable/include/library.h +++ b/doomsday/engine/portable/include/library.h @@ -47,6 +47,12 @@ void Library_Init(void); */ void Library_Shutdown(void); +/** + * Closes the library handles of all game plugins. The library will be + * reopened automatically when needed. + */ +void Library_ReleaseGames(void); + /** * Defines an additional library @a dir where to look for dynamic libraries. */ diff --git a/doomsday/engine/portable/src/dd_main.c b/doomsday/engine/portable/src/dd_main.c index a6b4ace58d..77925cde0d 100644 --- a/doomsday/engine/portable/src/dd_main.c +++ b/doomsday/engine/portable/src/dd_main.c @@ -1099,6 +1099,14 @@ boolean DD_ChangeGame2(Game* game, boolean allowReload) Con_ClearDatabases(); + { // Tell the plugin it is being unloaded. + void* unloader = DD_FindEntryPoint(Game_PluginId(theGame), "DP_Unload"); +#ifdef _DEBUG + Con_Message("DD_ChangeGame2: Calling DP_Unload (%p)\n", unloader); +#endif + if(unloader) ((pluginfunc_t)unloader)(); + } + // The current game is now the special "null-game". theGame = nullGame; @@ -1133,6 +1141,8 @@ boolean DD_ChangeGame2(Game* game, boolean allowReload) } ) + Library_ReleaseGames(); + if(!exchangeEntryPoints(Game_PluginId(game))) { DD_ComposeMainWindowTitle(buf); @@ -1149,6 +1159,14 @@ boolean DD_ChangeGame2(Game* game, boolean allowReload) // This is now the current game. theGame = game; + { // Tell the plugin it is being unloaded. + void* loader = DD_FindEntryPoint(Game_PluginId(theGame), "DP_Load"); +#ifdef _DEBUG + Con_Message("DD_ChangeGame2: Calling DP_Load (%p)\n", loader); +#endif + if(loader) ((pluginfunc_t)loader)(); + } + DD_ComposeMainWindowTitle(buf); Sys_SetWindowTitle(windowIDX, buf); diff --git a/doomsday/engine/portable/src/library.c b/doomsday/engine/portable/src/library.c index b32ca00fc1..0470cbaf74 100644 --- a/doomsday/engine/portable/src/library.c +++ b/doomsday/engine/portable/src/library.c @@ -33,16 +33,20 @@ #include #include -typedef void* handle_t; +#define MAX_LIBRARIES 64 /// @todo Replace with a dynamic list. -static filename_t appDir; /// @todo Use ddstring_t -static ddstring_t* lastError; +typedef void* handle_t; struct library_s { ddstring_t* path; handle_t handle; + boolean isGamePlugin; }; +static filename_t appDir; /// @todo Use ddstring_t +static ddstring_t* lastError; +static Library* loadedLibs[MAX_LIBRARIES]; + static void getBundlePath(char* path, size_t len) { if(ArgCheckWith("-libdir", 1)) @@ -71,6 +75,34 @@ static void getBundlePath(char* path, size_t len) #endif } +static void addToLoaded(Library* lib) +{ + int i; + for(i = 0; i < MAX_LIBRARIES; ++i) + { + if(!loadedLibs[i]) + { + loadedLibs[i] = lib; + return; + } + } + assert(false); +} + +static void removeFromLoaded(Library* lib) +{ + int i; + for(i = 0; i < MAX_LIBRARIES; ++i) + { + if(loadedLibs[i] == lib) + { + loadedLibs[i] = 0; + return; + } + } + assert(false); +} + void Library_Init(void) { lastError = Str_NewStd(); @@ -81,7 +113,39 @@ void Library_Shutdown(void) { Str_Delete(lastError); lastError = 0; - /// @todo Unload all remaining libraries. + /// @todo Unload all remaining libraries? +} + +void Library_ReleaseGames(void) +{ + int i; + + for(i = 0; i < MAX_LIBRARIES; ++i) + { + Library* lib = loadedLibs[i]; + if(!lib) continue; + if(lib->isGamePlugin && lib->handle) + { +#ifdef _DEBUG + fprintf(stderr, "Library_ReleaseGames: Closing '%s'\n", Str_Text(lib->path)); +#endif + dlclose(lib->handle); + lib->handle = 0; + } + } +} + +static void reopenLibraryIfNeeded(Library* lib) +{ + assert(lib); + if(!lib->handle) + { +#ifdef _DEBUG + fprintf(stderr, "reopenLibraryIfNeeded: Opening '%s'\n", Str_Text(lib->path)); +#endif + lib->handle = dlopen(Str_Text(lib->path), RTLD_NOW); + assert(lib->handle); + } } Library* Library_New(const char *fileName) @@ -130,6 +194,17 @@ Library* Library_New(const char *fileName) lib->handle = handle; lib->path = Str_NewStd(); Str_Set(lib->path, bundlePath); + + addToLoaded(lib); + + // Symbols from game plugins conflict with each other, so we have to + // keep track of them. + /// @todo Needs a more generic way to detect the type of plugin. + if(Library_Symbol(lib, "G_RegisterGames")) + { + lib->isGamePlugin = true; + } + return lib; } @@ -141,12 +216,14 @@ void Library_Delete(Library *lib) dlclose(lib->handle); } Str_Delete(lib->path); + removeFromLoaded(lib); free(lib); } void* Library_Symbol(Library* lib, const char* symbolName) { assert(lib); + reopenLibraryIfNeeded(lib); void* ptr = dlsym(lib->handle, symbolName); if(!ptr) { diff --git a/doomsday/plugins/jdoom/api/jdoom.def b/doomsday/plugins/jdoom/api/jdoom.def index bfeb9af549..861ffba711 100644 --- a/doomsday/plugins/jdoom/api/jdoom.def +++ b/doomsday/plugins/jdoom/api/jdoom.def @@ -3,3 +3,5 @@ LIBRARY JDOOM EXPORTS DP_Initialize @1 GetGameAPI @2 + DP_Load @3 + DP_Unload @4 diff --git a/doomsday/plugins/jdoom/src/d_api.c b/doomsday/plugins/jdoom/src/d_api.c index 555eb031fb..10084a2aa3 100644 --- a/doomsday/plugins/jdoom/src/d_api.c +++ b/doomsday/plugins/jdoom/src/d_api.c @@ -245,5 +245,14 @@ game_export_t* GetGameAPI(game_import_t* imports) void DP_Initialize() { Plug_AddHook(HOOK_STARTUP, G_RegisterGames); +} + +void DP_Load(void) +{ Plug_AddHook(HOOK_VIEWPORT_RESHAPE, R_UpdateViewport); } + +void DP_Unload(void) +{ + Plug_RemoveHook(HOOK_VIEWPORT_RESHAPE, R_UpdateViewport); +}