plugins: follow-up prev, log thread name when loading plugins
Correction to comment in prev commit (and removing it here): spec.loader.exec_module does not spawn new threads, it simply executes the module in the current thread. I got confused but turns out "load_plugin" itself is sometimes not called from the main thread. Specifically (e.g.), since the recent wizard rewrite, in the qt gui, the wizard loads the hww plugins from a new thread. This now better explains the macos hww crashes: they had started appearing because we upgraded hidapi (which made it more sensitive to having to import from main thread) AND scanning(->importing) from the wizard no longer happened on the main thread after the rewrite. Plugins should be thread-safe in terms of where they are imported from. Let's log the importer thread's name (added here), to help recognise related threading issues.
This commit is contained in:
@@ -131,6 +131,9 @@ class Plugins(DaemonThread):
|
|||||||
return len(self.plugins)
|
return len(self.plugins)
|
||||||
|
|
||||||
def load_plugin(self, name) -> 'BasePlugin':
|
def load_plugin(self, name) -> 'BasePlugin':
|
||||||
|
"""Imports the code of the given plugin.
|
||||||
|
note: can be called from any thread.
|
||||||
|
"""
|
||||||
if name in self.plugins:
|
if name in self.plugins:
|
||||||
return self.plugins[name]
|
return self.plugins[name]
|
||||||
full_name = f'electrum.plugins.{name}.{self.gui_name}'
|
full_name = f'electrum.plugins.{name}.{self.gui_name}'
|
||||||
@@ -140,13 +143,13 @@ class Plugins(DaemonThread):
|
|||||||
% (self.gui_name, name))
|
% (self.gui_name, name))
|
||||||
try:
|
try:
|
||||||
module = importlib.util.module_from_spec(spec)
|
module = importlib.util.module_from_spec(spec)
|
||||||
spec.loader.exec_module(module) # note: imports the plugin code in a *different* thread
|
spec.loader.exec_module(module)
|
||||||
plugin = module.Plugin(self, self.config, name)
|
plugin = module.Plugin(self, self.config, name)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise Exception(f"Error loading {name} plugin: {repr(e)}") from e
|
raise Exception(f"Error loading {name} plugin: {repr(e)}") from e
|
||||||
self.add_jobs(plugin.thread_jobs())
|
self.add_jobs(plugin.thread_jobs())
|
||||||
self.plugins[name] = plugin
|
self.plugins[name] = plugin
|
||||||
self.logger.info(f"loaded {name}")
|
self.logger.info(f"loaded plugin {name!r}. (from thread: {threading.current_thread().name!r})")
|
||||||
return plugin
|
return plugin
|
||||||
|
|
||||||
def close_plugin(self, plugin):
|
def close_plugin(self, plugin):
|
||||||
|
|||||||
Reference in New Issue
Block a user