# HG changeset patch # User Jun Wu <qu...@fb.com> # Date 1485794838 0 # Mon Jan 30 16:47:18 2017 +0000 # Node ID 0f9c5c49ad7ac321f6fecb4ca90121969bb038d4 # Parent ea5353feeec3c2eddd7e4acfd398baddaf37b3e4 # Available At https://bitbucket.org/quark-zju/hg-draft # hg pull https://bitbucket.org/quark-zju/hg-draft -r 0f9c5c49ad7a 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 prevent new connections and handling all pending connections before exiting. diff --git a/mercurial/commandserver.py b/mercurial/commandserver.py --- a/mercurial/commandserver.py +++ b/mercurial/commandserver.py @@ -412,5 +412,9 @@ class unixservicehandler(object): def unlinksocket(self, address): - os.unlink(address) + try: + os.unlink(address) + except OSError as ex: + if ex.errno != errno.ENOENT: + raise def printbanner(self, address): @@ -471,9 +475,17 @@ class unixforkingservice(object): def _mainloop(self): + exiting = False h = self._servicehandler - while not h.shouldexit(): + while True: + if not exiting and h.shouldexit(): + # prevent accepting new connections + self._servicehandler.unlinksocket(self.address) + exiting = True try: ready = select.select([self._sock], [], [], h.pollinterval)[0] if not ready: + # only exit if we have no more connections to handle + if exiting: + break continue conn, _addr = self._sock.accept() _______________________________________________ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel