changeset 34448:5385b76fd1fd

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
author Jun Wu <quark@fb.com>
date Mon, 02 Oct 2017 20:23:25 -0700
parents b0c97e44576f
children 1f5bd3e1a7fe
files hgext/zeroconf/Zeroconf.py
diffstat 1 files changed, 11 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- 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():