[Jython-checkins] jython: Close sockets more carefully. Fixes #2470, #2471

jim.baker jython-checkins at python.org
Wed Feb 24 00:55:31 EST 2016


https://hg.python.org/jython/rev/63a2a4f6aa42
changeset:   7908:63a2a4f6aa42
user:        Nick Bailey <nickmbailey at gmail.com>
date:        Tue Feb 23 22:53:40 2016 -0700
summary:
  Close sockets more carefully. Fixes #2470, #2471

Fixes two somewhat related issues with respect to closing sockets:

* Peer closes do not mean the socket is no longer writable, just that
  the peer has closed its half of the channel (half-closed). Fixed by
  always allowing the channel to be written to once half closed (#2470).

* Server sockets now shutdown their thread pools asynchronously with
  their closing, so as to not deadlock (#2471).

files:
  Lib/_socket.py |  52 +++++++++++++++++++------------------
  1 files changed, 27 insertions(+), 25 deletions(-)


diff --git a/Lib/_socket.py b/Lib/_socket.py
--- a/Lib/_socket.py
+++ b/Lib/_socket.py
@@ -729,6 +729,7 @@
         self.selectors = CopyOnWriteArrayList()
         self.options = {}  # deferred options until bootstrap
         self.peer_closed = False
+        self.channel_closed = False
 
         # Reference count this underlying socket
         self.open_lock = Lock()
@@ -875,12 +876,13 @@
         if self.connect_handlers:
             self.channel.pipeline().addLast(self.python_inbound_handler)
         
-        def peer_closed(x):
+        def _peer_closed(x):
             log.debug("Peer closed channel %s", x, extra={"sock": self})
+            self.channel_closed = True
             self.incoming.put(_PEER_CLOSED)
             self._notify_selectors(hangup=True)
 
-        self.channel.closeFuture().addListener(peer_closed)
+        self.channel.closeFuture().addListener(_peer_closed)
 
     def connect(self, addr):
         # Unwrapped sockets can immediately perform the post-connect step
@@ -1054,30 +1056,30 @@
 
             if self.channel is None:
                 return
+            
+            close_future = self.channel.close()
+            if close_future.isSuccess():
+                close_future.addListener(self._finish_closing)
 
-            try:
-                self.channel.close().sync()
-            except RejectedExecutionException:
-                # Do not care about tasks that attempt to schedule after close
-                pass
-            if self.socket_type == SERVER_SOCKET:
-                log.debug("Shutting down server socket parent group", extra={"sock": self})
-                self.parent_group.shutdownGracefully(0, 100, TimeUnit.MILLISECONDS)
-                self.accepted_children -= 1
-                while True:
-                    child = self.child_queue.poll()
-                    if child is None:
-                        break
-                    log.debug("Closed child socket %s not yet accepted", child, extra={"sock": self})
-                    child.close()
-            else:
-                msgs = []
-                self.incoming.drainTo(msgs)
-                for msg in msgs:
-                    if msg is not _PEER_CLOSED:
-                        msg.release()
+    def _finish_closing(self, _):
+        if self.socket_type == SERVER_SOCKET:
+            log.debug("Shutting down server socket parent group", extra={"sock": self})
+            self.parent_group.shutdownGracefully(0, 100, TimeUnit.MILLISECONDS)
+            self.accepted_children -= 1
+            while True:
+                child = self.child_queue.poll()
+                if child is None:
+                    break
+                log.debug("Closed child socket %s not yet accepted", child, extra={"sock": self})
+                child.close()
+        else:
+            msgs = []
+            self.incoming.drainTo(msgs)
+            for msg in msgs:
+                if msg is not _PEER_CLOSED:
+                    msg.release()
 
-            log.debug("Closed socket", extra={"sock": self})
+        log.debug("Closed socket", extra={"sock": self})
 
     def shutdown(self, how):
         log.debug("Got request to shutdown socket how=%s", how, extra={"sock": self})
@@ -1121,7 +1123,7 @@
         return 0
 
     def _writable(self):
-        return self.channel and self.channel.isActive() and self.channel.isWritable()
+        return self.channel_closed or (self.channel and self.channel.isActive() and self.channel.isWritable())
 
     can_write = _writable
 

-- 
Repository URL: https://hg.python.org/jython


More information about the Jython-checkins mailing list