electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit c31ae86bb857c27aea3ab615b649dd17b392179e
parent ea22d0073ea5f61d53449a7afd072c3fd78003e8
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:
Mrun_electrum | 40+++++++++++++++++++++++++++++++++-------
1 file changed, 33 insertions(+), 7 deletions(-)

diff --git a/run_electrum b/run_electrum @@ -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__)) @@ -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__) @@ -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] @@ -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 @@ -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) @@ -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: @@ -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) @@ -438,3 +460,7 @@ if __name__ == '__main__': elif result is not None: print_msg(json_encode(result)) sys_exit(0) + + +if __name__ == '__main__': + main()