tMerge pull request #6634 from SomberNight/202010_fix_main_script_hanging - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit c31ae86bb857c27aea3ab615b649dd17b392179e DIR parent ea22d0073ea5f61d53449a7afd072c3fd78003e8 HTML Author: ThomasV <thomasv@electrum.org> Date: Wed, 28 Oct 2020 16:22:39 +0100 Merge pull request #6634 from SomberNight/202010_fix_main_script_hanging fix main script hanging (not exiting after exception) in some cases Diffstat: M run_electrum | 40 +++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 7 deletions(-) --- DIR diff --git a/run_electrum b/run_electrum t@@ -37,7 +37,7 @@ if sys.version_info[:3] < _min_python_version_tuple: import warnings import asyncio -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Optional script_dir = os.path.dirname(os.path.realpath(__file__)) t@@ -95,6 +95,8 @@ from electrum import keystore from electrum.util import create_and_start_event_loop if TYPE_CHECKING: + import threading + from electrum.plugin import Plugins _logger = get_logger(__name__) t@@ -113,7 +115,7 @@ def prompt_password(prompt, confirm=True): return password -def init_cmdline(config_options, wallet_path, server): +def init_cmdline(config_options, wallet_path, server, *, config: 'SimpleConfig'): cmdname = config.get('cmd') cmd = known_commands[cmdname] t@@ -259,13 +261,20 @@ def init_plugins(config, gui_name): from electrum.plugin import Plugins return Plugins(config, gui_name) + +loop = None # type: Optional[asyncio.AbstractEventLoop] +stop_loop = None # type: Optional[asyncio.Future] +loop_thread = None # type: Optional[threading.Thread] + def sys_exit(i): # stop event loop and exit - loop.call_soon_threadsafe(stop_loop.set_result, 1) - loop_thread.join(timeout=1) + if loop: + loop.call_soon_threadsafe(stop_loop.set_result, 1) + loop_thread.join(timeout=1) sys.exit(i) -if __name__ == '__main__': + +def main(): # The hook will only be used in the Qt GUI right now util.setup_thread_excepthook() # on macOS, delete Process Serial Number arg generated for apps launched in Finder t@@ -368,8 +377,21 @@ if __name__ == '__main__': os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) + global loop, stop_loop, loop_thread loop, stop_loop, loop_thread = create_and_start_event_loop() + try: + handle_cmd( + cmdname=cmdname, + config=config, + config_options=config_options, + ) + except Exception: + _logger.exception("") + sys_exit(1) + + +def handle_cmd(*, cmdname: str, config: 'SimpleConfig', config_options: dict): if cmdname == 'gui': configure_logging(config) fd = daemon.get_file_descriptor(config) t@@ -404,7 +426,7 @@ if __name__ == '__main__': cmd = known_commands[cmdname] wallet_path = config.get_wallet_path() if not config.get('offline'): - init_cmdline(config_options, wallet_path, True) + init_cmdline(config_options, wallet_path, True, config=config) timeout = config.get('timeout', 60) if timeout: timeout = int(timeout) try: t@@ -421,7 +443,7 @@ if __name__ == '__main__': if cmd.requires_network: print_msg("This command cannot be run offline") sys_exit(1) - init_cmdline(config_options, wallet_path, False) + init_cmdline(config_options, wallet_path, False, config=config) plugins = init_plugins(config, 'cmdline') coro = run_offline_command(config, config_options, plugins) fut = asyncio.run_coroutine_threadsafe(coro, loop) t@@ -438,3 +460,7 @@ if __name__ == '__main__': elif result is not None: print_msg(json_encode(result)) sys_exit(0) + + +if __name__ == '__main__': + main()