mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
[3.12] gh-79033: Try to fix asyncio.Server.wait_closed() again (GH-111336) (#111424)
gh-79033: Try to fix asyncio.Server.wait_closed() again (GH-111336)
* Try to fix asyncio.Server.wait_closed() again
I identified the condition that `wait_closed()` is intended
to wait for: the server is closed *and* there are no more
active connections.
When this condition first becomes true, `_wakeup()` is called
(either from `close()` or from `_detach()`) and it sets `_waiters`
to `None`. So we just check for `self._waiters is None`; if it's
not `None`, we know we have to wait, and do so.
A problem was that the new test introduced in 3.12 explicitly
tested that `wait_closed()` returns immediately when the server
is *not* closed but there are currently no active connections.
This was a mistake (probably a misunderstanding of the intended
semantics). I've fixed the test, and added a separate test that
checks exactly for this scenario.
I also fixed an oddity where in `_wakeup()` the result of the
waiter was set to the waiter itself. This result is not used
anywhere and I changed this to `None`, to avoid a GC cycle.
* Update Lib/asyncio/base_events.py
---------
(cherry picked from commit 2655369559
)
Co-authored-by: Guido van Rossum <guido@python.org>
Co-authored-by: Carol Willing <carolcode@willingconsulting.com>
This commit is contained in:
parent
cf29a2f25e
commit
2e5d4e24eb
4 changed files with 67 additions and 9 deletions
|
@ -305,7 +305,7 @@ class Server(events.AbstractServer):
|
|||
self._waiters = None
|
||||
for waiter in waiters:
|
||||
if not waiter.done():
|
||||
waiter.set_result(waiter)
|
||||
waiter.set_result(None)
|
||||
|
||||
def _start_serving(self):
|
||||
if self._serving:
|
||||
|
@ -377,7 +377,27 @@ class Server(events.AbstractServer):
|
|||
self._serving_forever_fut = None
|
||||
|
||||
async def wait_closed(self):
|
||||
if self._waiters is None or self._active_count == 0:
|
||||
"""Wait until server is closed and all connections are dropped.
|
||||
|
||||
- If the server is not closed, wait.
|
||||
- If it is closed, but there are still active connections, wait.
|
||||
|
||||
Anyone waiting here will be unblocked once both conditions
|
||||
(server is closed and all connections have been dropped)
|
||||
have become true, in either order.
|
||||
|
||||
Historical note: In 3.11 and before, this was broken, returning
|
||||
immediately if the server was already closed, even if there
|
||||
were still active connections. An attempted fix in 3.12.0 was
|
||||
still broken, returning immediately if the server was still
|
||||
open and there were no active connections. Hopefully in 3.12.1
|
||||
we have it right.
|
||||
"""
|
||||
# Waiters are unblocked by self._wakeup(), which is called
|
||||
# from two places: self.close() and self._detach(), but only
|
||||
# when both conditions have become true. To signal that this
|
||||
# has happened, self._wakeup() sets self._waiters to None.
|
||||
if self._waiters is None:
|
||||
return
|
||||
waiter = self._loop.create_future()
|
||||
self._waiters.append(waiter)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue