From f3102af1959a3f78b6cdf91a6f43c30aad732e64 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Thu, 12 Jan 2023 15:00:10 +0000 Subject: [PATCH] util: create_and_start_event_loop() to wait until loop starts With a PyCharm debugger attached, sometimes the python process is so CPU-starved for me that create_and_start_event_loop() returned before the event loop actually started, resulting in weird errors. I guess this could happen even without a debugger attached on a sufficiently slow CPU. ``` ...\electrum\electrum\wallet.py:3580: in restore_wallet_from_text wallet = Wallet(db, storage, config=config) ...\electrum\electrum\wallet.py:3501: in __new__ wallet = WalletClass(db, storage, config=config) ...\electrum\electrum\wallet.py:3345: in __init__ Deterministic_Wallet.__init__(self, db, storage, config=config) ...\electrum\electrum\wallet.py:3135: in __init__ self.synchronize() ...\electrum\electrum\wallet.py:3283: in synchronize count += self.synchronize_sequence(False) ...\electrum\electrum\wallet.py:3267: in synchronize_sequence self.create_new_address(for_change) ...\electrum\electrum\wallet.py:3254: in create_new_address self.adb.add_address(address) ...\electrum\electrum\address_synchronizer.py:213: in add_address self.up_to_date_changed() ...\electrum\electrum\address_synchronizer.py:680: in up_to_date_changed util.trigger_callback('adb_set_up_to_date', self) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = event = 'adb_set_up_to_date' args = (,) def trigger_callback(self, event, *args): """Trigger a callback with given arguments. Can be called from any thread. The callback itself will get scheduled on the event loop. """ if self.asyncio_loop is None: self.asyncio_loop = get_asyncio_loop() > assert self.asyncio_loop.is_running(), "event loop not running" E AssertionError: event loop not running ...\electrum\electrum\util.py:1734: AssertionError ``` --- electrum/util.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/electrum/util.py b/electrum/util.py index e2e5cdffe..6b4a75f98 100644 --- a/electrum/util.py +++ b/electrum/util.py @@ -1556,13 +1556,21 @@ def create_and_start_event_loop() -> Tuple[asyncio.AbstractEventLoop, _asyncio_event_loop = None loop.set_exception_handler(on_exception) - # loop.set_debug(1) + # loop.set_debug(True) stopping_fut = loop.create_future() loop_thread = threading.Thread( target=run_event_loop, name='EventLoop', ) loop_thread.start() + # Wait until the loop actually starts. + # On a slow PC, or with a debugger attached, this can take a few dozens of ms, + # and if we returned without a running loop, weird things can happen... + t0 = time.monotonic() + while not loop.is_running(): + time.sleep(0.01) + if time.monotonic() - t0 > 5: + raise Exception("been waiting for 5 seconds but asyncio loop would not start!") return loop, stopping_fut, loop_thread