Skip to content

Commit 794a753

Browse files
committed
Merge bitcoin/bitcoin#35583: test: close the listeners before terminating the event loop
e4d80e7 test: close the loop after the network thread has completed (Vasil Dimov) 29fba5d test: close the listeners before terminating the event loop (Vasil Dimov) Pull request description: Whenever a test creates a new `P2PInterface` object a new listener is created inside `NetworkThread.create_listen_server()` by calling `cls.network_event_loop.create_server()`. These listeners are never closed which might result in: ``` 2026-06-10T22:13:35.3934880Z Task was destroyed but it is pending! 2026-06-10T22:13:35.3936020Z task: <Task pending name='Task-54' coro=<BaseSelectorEventLoop._accept_connection2() done, defined at /opt/homebrew/Cellar/python@3.14/3.14.5/Frameworks/Python.framework/Versions/3.14/lib/python3.14/asyncio/selector_events.py:217> wait_for=<Future finished result=None>> ``` when the event loop is closed. Fix that by closing the listeners. Fixes: bitcoin/bitcoin#35508 ACKs for top commit: andrewtoth: ACK e4d80e7 sedited: ACK e4d80e7 Tree-SHA512: b93d06526b4eb31ac445a1a0e379e5ec947661f8ea29f2e07ac88b9e4760b0cc5348638b320ab8d60735f34fc163fcdd18eba42b20e0a7726a98a5136433bd64
2 parents f6b3f2f + e4d80e7 commit 794a753

1 file changed

Lines changed: 18 additions & 1 deletion

File tree

  • test/functional/test_framework

test/functional/test_framework/p2p.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,7 @@ def __init__(self):
748748

749749
NetworkThread.listeners = {}
750750
NetworkThread.protos = {}
751+
NetworkThread.protos_accept_done = []
751752

752753
def run(self):
753754
"""Start the network thread."""
@@ -756,10 +757,25 @@ def run(self):
756757

757758
def close(self, *, timeout):
758759
"""Close the connections and network event loop."""
760+
for p in NetworkThread.protos_accept_done:
761+
p.peer_disconnect()
762+
NetworkThread.protos_accept_done.clear()
763+
764+
listeners = list(NetworkThread.listeners.values())
765+
NetworkThread.listeners.clear()
766+
767+
async def close_listeners():
768+
for listener in listeners:
769+
listener.close()
770+
for listener in listeners:
771+
await listener.wait_closed()
772+
future = asyncio.run_coroutine_threadsafe(close_listeners(), self.network_event_loop)
773+
future.result(timeout=timeout)
774+
759775
self.network_event_loop.call_soon_threadsafe(self.network_event_loop.stop)
760776
wait_until_helper_internal(lambda: not self.network_event_loop.is_running(), timeout=timeout)
761-
self.network_event_loop.close()
762777
self.join(timeout)
778+
self.network_event_loop.close()
763779
# Safe to remove event loop.
764780
NetworkThread.network_event_loop = None
765781

@@ -795,6 +811,7 @@ def peer_protocol():
795811
response = cls.protos.get((addr, port))
796812
# remove protocol function from dict only when reconnection doesn't need to happen/already happened
797813
if not proto.reconnect:
814+
cls.protos_accept_done.append(response)
798815
cls.protos[(addr, port)] = None
799816
return response
800817

0 commit comments

Comments
 (0)