Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/commandserver.py @ 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 | 48dea083f66d |
comparison
equal
deleted
inserted
replaced
30919:a95fc01aaffe | 30920:b1b36c6499c2 |
---|---|
475 self._mainloop() | 475 self._mainloop() |
476 finally: | 476 finally: |
477 self._cleanup() | 477 self._cleanup() |
478 | 478 |
479 def _mainloop(self): | 479 def _mainloop(self): |
480 exiting = False | |
480 h = self._servicehandler | 481 h = self._servicehandler |
481 while not h.shouldexit(): | 482 while True: |
483 if not exiting and h.shouldexit(): | |
484 # clients can no longer connect() to the domain socket, so | |
485 # we stop queuing new requests. | |
486 # for requests that are queued (connect()-ed, but haven't been | |
487 # accept()-ed), handle them before exit. otherwise, clients | |
488 # waiting for recv() will receive ECONNRESET. | |
489 self._unlinksocket() | |
490 exiting = True | |
482 try: | 491 try: |
483 ready = select.select([self._sock], [], [], h.pollinterval)[0] | 492 ready = select.select([self._sock], [], [], h.pollinterval)[0] |
484 if not ready: | 493 if not ready: |
494 # only exit if we completed all queued requests | |
495 if exiting: | |
496 break | |
485 continue | 497 continue |
486 conn, _addr = self._sock.accept() | 498 conn, _addr = self._sock.accept() |
487 except (select.error, socket.error) as inst: | 499 except (select.error, socket.error) as inst: |
488 if inst.args[0] == errno.EINTR: | 500 if inst.args[0] == errno.EINTR: |
489 continue | 501 continue |