From 50fd1b6b5fee75b65fe322637e34d36bcf189af4 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Tue, 6 Jan 2015 02:55:03 +0200 Subject: [PATCH] Don't let one unload currently used core (crashes the emulator) --- include/core/loadlib.hpp | 2 +- include/interface/romtype.hpp | 8 ++++++++ include/library/loadlib.hpp | 30 ++++++++++++++++++++++++++++-- src/core/loadlib.cpp | 18 +++++++++++++++--- src/interface/romtype.cpp | 12 ++++++++++++ src/library/loadlib.cpp | 5 +++++ 6 files changed, 69 insertions(+), 6 deletions(-) diff --git a/include/core/loadlib.hpp b/include/core/loadlib.hpp index 0e5985e1..d7fe9ab2 100644 --- a/include/core/loadlib.hpp +++ b/include/core/loadlib.hpp @@ -6,6 +6,6 @@ void handle_post_loadlibrary(); void autoload_libraries(void(*on_error)(const std::string& libname, const std::string& err, bool system) = NULL); void with_loaded_library(const loadlib::module& l); -void with_unloaded_library(loadlib::module& l); +bool with_unloaded_library(loadlib::module& l); #endif diff --git a/include/interface/romtype.hpp b/include/interface/romtype.hpp index 6ffc3fe3..868022ab 100644 --- a/include/interface/romtype.hpp +++ b/include/interface/romtype.hpp @@ -9,6 +9,7 @@ #include "interface/setting.hpp" #include "library/framebuffer.hpp" #include "library/threads.hpp" +#include "library/loadlib.hpp" struct core_region; struct core_type; @@ -18,6 +19,11 @@ struct core_romimage_info; struct core_core; /** + * The module currently being loaded. + */ +extern thread_local const loadlib::module* module_loading; + +/** * Interface device register. */ struct interface_device_reg @@ -356,6 +362,7 @@ struct core_core std::vector get_trace_cpus(); void debug_reset(); bool isnull(); + bool safe_to_unload(loadlib::module& mod) { return !mod.is_marked(this); } protected: /** * Get the name of the core. @@ -611,6 +618,7 @@ public: std::vector get_trace_cpus() { return core->get_trace_cpus(); } void debug_reset() { core->debug_reset(); } bool isnull() { return core->isnull(); } + bool safe_to_unload(loadlib::module& mod) { return core->safe_to_unload(mod); } protected: /** * Load a ROM slot set. Changes the ROM currently loaded for core. diff --git a/include/library/loadlib.hpp b/include/library/loadlib.hpp index 3ea16867..6f858dbe 100644 --- a/include/library/loadlib.hpp +++ b/include/library/loadlib.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "threads.hpp" #if defined(_WIN32) || defined(_WIN64) @@ -36,7 +37,14 @@ public: */ library(const std::string& filename) throw(std::bad_alloc, std::runtime_error) { - lib = new internal(filename); + try { + set_loading(this); + lib = new internal(filename); + set_loading(NULL); + } catch(...) { + set_loading(NULL); + throw; + } } /** * Unload a library. @@ -94,7 +102,14 @@ public: return *this; } std::string get_libname() const { return lib->libname; } + void mark(const void* obj) const { if(lib) lib->mark(obj); } + bool is_marked(const void* obj) const { return lib ? lib->is_marked(obj) : false; } +/** + * Get currently loading library, or NULL if nothing is loading. + */ + static library* loading() throw(); private: + void set_loading(library* lib) throw(std::bad_alloc); struct internal { internal(const std::string& filename) throw(std::bad_alloc, std::runtime_error); @@ -109,8 +124,11 @@ private: #endif size_t refs; std::string libname; + void mark(const void* obj) { marked.insert(obj); } + bool is_marked(const void* obj) { return marked.count(obj); } + std::set marked; }; - internal* lib; + mutable internal* lib; }; /** @@ -171,6 +189,14 @@ public: * Run all not ran initialization functions. */ static void run_initializers(); +/** + * Mark object (only works for libraries). + */ + void mark(const void* obj) const { if(dynamic) lib.mark(obj); } +/** + * Is object marked (only works for libraries)? + */ + bool is_marked(const void* obj) const { return dynamic ? lib.is_marked(obj) : false; } private: bool dynamic; library lib; diff --git a/src/core/loadlib.cpp b/src/core/loadlib.cpp index 1f30d331..3591bde7 100644 --- a/src/core/loadlib.cpp +++ b/src/core/loadlib.cpp @@ -1,9 +1,11 @@ #include "cmdhelp/loadlib.hpp" #include "core/command.hpp" #include "core/dispatch.hpp" +#include "core/instance.hpp" #include "core/loadlib.hpp" #include "core/messages.hpp" #include "core/misc.hpp" +#include "core/rom.hpp" #include "interface/c-interface.hpp" #include "interface/romtype.hpp" #include "library/command.hpp" @@ -92,16 +94,24 @@ void with_loaded_library(const loadlib::module& l) //This wasn't libopus. } try { + module_loading = &l; try_init_c_module(l); + module_loading = NULL; } catch(...) { + module_loading = NULL; //Ignored. } messages << "Loaded library '" << l.get_libname() << "'" << std::endl; modules[next_mod++] = const_cast(&l); } -void with_unloaded_library(loadlib::module& l) +bool with_unloaded_library(loadlib::module& l) { + //Check that this module is not needed. + if(!CORE().rom->get_internal_rom_type().safe_to_unload(l)) { + messages << "Current core is from this module, can't unload" << std::endl; + return false; + } try { try_uninit_c_module(l); } catch(...) { @@ -110,6 +120,8 @@ void with_unloaded_library(loadlib::module& l) //Spot removed cores. notify_new_core(); delete &l; + notify_new_core(); //In case only unload made it go away. + return true; } namespace @@ -169,8 +181,8 @@ namespace unsigned libid = parse_value(args); if(!modules.count(libid)) throw std::runtime_error("No such library loaded"); - with_unloaded_library(*modules[libid]); - modules.erase(libid); + if(with_unloaded_library(*modules[libid])) + modules.erase(libid); }); command::fnptr<> CMD_list_library(lsnes_cmds, CLOADLIB::list, diff --git a/src/interface/romtype.cpp b/src/interface/romtype.cpp index 2a231a02..b635a67f 100644 --- a/src/interface/romtype.cpp +++ b/src/interface/romtype.cpp @@ -12,8 +12,18 @@ #include #include +thread_local const loadlib::module* module_loading; + namespace { + void mark_against_loading(const void* obj) + { + auto i = module_loading; + if(i) i->mark(obj); + auto j = loadlib::library::loading(); + if(j) j->mark(obj); + } + bool install_handlers_automatically; std::map& sysreg_mapping() @@ -374,6 +384,7 @@ core_core::core_core(std::initializer_list ports, std::initiali uninitialized_cores_set().insert(this); all_cores_set().insert(this); new_core_flag = true; + mark_against_loading(this); } core_core::core_core(std::vector ports, std::vector x_actions) @@ -387,6 +398,7 @@ core_core::core_core(std::vector ports, std::vector #include +#include #if !defined(NO_DLFCN) && !defined(_WIN32) && !defined(_WIN64) #include @@ -17,6 +18,7 @@ threads::lock& global_mutex() namespace { + thread_local library* currently_loading; #if defined(_WIN32) || defined(_WIN64) std::string callsign = "dynamic link library"; std::string callsign_ext = "dll"; @@ -120,6 +122,9 @@ const std::string& library::extension() throw() return callsign_ext; } +library* library::loading() throw() { return currently_loading; } +void library::set_loading(library* lib) throw(std::bad_alloc) { currently_loading = lib; } + namespace { std::list& module_queue() -- 2.11.4.GIT