# HG changeset patch # User Jun Wu # Date 1507001005 25200 # Node ID 5385b76fd1fd25668d609eab31726449b96d7965 # Parent b0c97e44576fbf2d3c7f14ff2582f9c67cf47148 zeroconf: do not crash if socket being read is closed by another thread In zeroconf/__init__.py, there is: server = Zeroconf.Zeroconf(ip) l = listener() Zeroconf.ServiceBrowser(server, "_hg._tcp.local.", l) time.sleep(1) server.close() `server.close()` closes the underlying socket while the `ServiceBrowser` may still have a background thread reading the socket. There could be a race condition where the reading thread reads the closed socket, resulting in EBADF crash. This patch catches the exception. This makes test-paths.t pass with chg. Differential Revision: https://phab.mercurial-scm.org/D919 diff -r b0c97e44576f -r 5385b76fd1fd hgext/zeroconf/Zeroconf.py --- a/hgext/zeroconf/Zeroconf.py Mon Oct 02 19:31:33 2017 -0700 +++ b/hgext/zeroconf/Zeroconf.py Mon Oct 02 20:23:25 2017 -0700 @@ -80,6 +80,7 @@ __email__ = "paul at scott dash murphy dot com" __version__ = "0.12" +import errno import itertools import select import socket @@ -937,7 +938,16 @@ self.zeroconf.engine.addReader(self, self.zeroconf.socket) def handle_read(self): - data, (addr, port) = self.zeroconf.socket.recvfrom(_MAX_MSG_ABSOLUTE) + data = addr = port = None + sock = self.zeroconf.socket + try: + data, (addr, port) = sock.recvfrom(_MAX_MSG_ABSOLUTE) + except socket.error as e: + if e.errno == errno.EBADF: + # some other thread may close the socket + return + else: + raise self.data = data msg = DNSIncoming(data) if msg.isQuery():