commit 3be5b4b00fadb341742b4fcb5e30fdb4d35decbd
parent 129460857132fdf23978544cb14b810a06394914
Author: SomberNight <somber.night@protonmail.com>
Date: Thu, 20 Sep 2018 21:07:31 +0200
network: fix some threading issues
Diffstat:
2 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/electrum/interface.py b/electrum/interface.py
@@ -369,8 +369,10 @@ class Interface(PrintError):
await self.session.send_request('server.ping')
def close(self):
- self.fut.cancel()
- asyncio.get_event_loop().create_task(self.group.cancel_remaining())
+ async def job():
+ self.fut.cancel()
+ await self.group.cancel_remaining()
+ asyncio.run_coroutine_threadsafe(job(), self.network.asyncio_loop)
async def run_fetch_blocks(self):
header_queue = asyncio.Queue()
diff --git a/electrum/network.py b/electrum/network.py
@@ -260,11 +260,11 @@ class Network(PrintError):
with self.callback_lock:
callbacks = self.callbacks[event][:]
for callback in callbacks:
+ # FIXME: if callback throws, we will lose the traceback
if asyncio.iscoroutinefunction(callback):
- # FIXME: if callback throws, we will lose the traceback
asyncio.run_coroutine_threadsafe(callback(event, *args), self.asyncio_loop)
else:
- callback(event, *args)
+ self.asyncio_loop.call_soon_threadsafe(callback, event, *args)
def read_recent_servers(self):
if not self.config.path:
@@ -425,7 +425,7 @@ class Network(PrintError):
def start_random_interface(self):
with self.interface_lock:
- exclude_set = self.disconnected_servers.union(set(self.interfaces))
+ exclude_set = self.disconnected_servers | set(self.interfaces) | self.connecting
server = pick_random_server(self.get_servers(), self.protocol, exclude_set)
if server:
self.start_interface(server)
@@ -602,8 +602,8 @@ class Network(PrintError):
self.start_interface(old_server)
self.interface = i
- asyncio.get_event_loop().create_task(
- i.group.spawn(self.request_server_info(i)))
+ asyncio.run_coroutine_threadsafe(
+ i.group.spawn(self.request_server_info(i)), self.asyncio_loop)
self.trigger_callback('default_server_changed')
self.set_status('connected')
self.trigger_callback('network_updated')
@@ -647,21 +647,22 @@ class Network(PrintError):
except BaseException as e:
#import traceback
#traceback.print_exc()
- self.print_error(interface.server, "couldn't launch because", str(e), str(type(e)))
+ self.print_error(server, "couldn't launch because", str(e), str(type(e)))
# note: connection_down will not call interface.close() as
# interface is not yet in self.interfaces. OTOH, calling
# interface.close() here will sometimes raise deep inside the
# asyncio internal select.select... instead, interface will close
# itself when it detects the cancellation of interface.ready;
# however this might take several seconds...
- self.connection_down(interface.server)
+ self.connection_down(server)
return
+ else:
+ with self.interface_lock:
+ self.interfaces[server] = interface
finally:
- try: self.connecting.remove(server)
- except KeyError: pass
-
- with self.interface_lock:
- self.interfaces[server] = interface
+ with self.interface_lock:
+ try: self.connecting.remove(server)
+ except KeyError: pass
if server == self.default_server:
self.switch_to_interface(server)
@@ -819,6 +820,6 @@ class Network(PrintError):
self.switch_to_interface(self.default_server)
else:
if self.config.is_fee_estimates_update_required():
- await self.interface.group.spawn(self.request_fee_estimates(self.interface))
+ await self.interface.group.spawn(self.request_fee_estimates, self.interface)
await asyncio.sleep(0.1)