changeset 30920:b1b36c6499c2

commandserver: handle backlog before exiting Previously, when a chg server is exiting, it does not handle connected clients so clients may get ECONNRESET and crash: 1. client connect() # success 2. server shouldexit = True and exit 3. client recv() # ECONNRESET d7875bfbfccb makes this race condition easier to reproduce if a lot of short chg commands are started in parallel. This patch fixes the above issue by unlinking the socket path to stop queuing new connections and processing all pending connections before exit.
author Jun Wu <quark@fb.com>
date Wed, 08 Feb 2017 14:45:30 -0800
parents a95fc01aaffe
children 441705506d24
files mercurial/commandserver.py
diffstat 1 files changed, 13 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/commandserver.py	Wed Feb 08 14:37:38 2017 -0800
+++ b/mercurial/commandserver.py	Wed Feb 08 14:45:30 2017 -0800
@@ -477,11 +477,23 @@
             self._cleanup()
 
     def _mainloop(self):
+        exiting = False
         h = self._servicehandler
-        while not h.shouldexit():
+        while True:
+            if not exiting and h.shouldexit():
+                # clients can no longer connect() to the domain socket, so
+                # we stop queuing new requests.
+                # for requests that are queued (connect()-ed, but haven't been
+                # accept()-ed), handle them before exit. otherwise, clients
+                # waiting for recv() will receive ECONNRESET.
+                self._unlinksocket()
+                exiting = True
             try:
                 ready = select.select([self._sock], [], [], h.pollinterval)[0]
                 if not ready:
+                    # only exit if we completed all queued requests
+                    if exiting:
+                        break
                     continue
                 conn, _addr = self._sock.accept()
             except (select.error, socket.error) as inst: