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