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

297d89f2789e 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.
This commit is contained in:
Jun Wu 2017-02-08 14:45:30 -08:00
parent 59177ba177
commit 863f8667b5

View File

@ -477,11 +477,23 @@ class unixforkingservice(object):
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: