| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
…y-looping When the self-pipe socketpair of a BaseProactorEventLoop reaches a clean EOF (e.g. the OS tears the loopback connection down across a power or session state change on Windows), _loop_self_reading re-armed recv() on the dead socket, which completed immediately and rescheduled the callback forever, pinning one core at 100% CPU with nothing logged. Detect the EOF via the empty recv result and rebuild the socketpair instead: allocate the replacement first (so a failure leaves the previous state untouched), re-register signal.set_wakeup_fd on the new socket before closing the old one (mirroring close()), then arm the next read on the new socket so cross-thread wakeups keep working.
| Back | FazBrowse Home | New Git URL |
Summary
On Windows, BaseProactorEventLoop wakes itself through a self-pipe — a loopback TCP socketpair created by socket.socketpair(). If that connection reaches a clean EOF while the loop is running — for example the OS tears the idle loopback connection down across a power/session state change — _loop_self_reading re-armed recv() on the dead socket, which completed immediately and rescheduled the callback forever: one core pinned at 100% CPU, no exception raised, nothing logged, the process never recovers. Reproduced deterministically on main (3.16.0a0, self-built): 346,702 re-arms of _loop_self_reading during a 3-second idle sleep (a graceful loop._csock.shutdown(socket.SHUT_WR) models the OS teardown).
At EOF f.result() returns b'', which is not an exception, so control fell through to the else branch and armed a read that could never block again.
Fix: when the recv result is empty, rebuild the socketpair instead of re-arming on the dead one:
Verification (real Windows machine, self-built 3.16.0a0 from the commit this PR is based on)
Out of scope / follow-ups