Issue2471
 
            
            
            
Created on 2016-02-22.23:04:32 by nickmbailey, last changed 2016-03-14.16:40:48 by zyasoft. 
 |
 
   | msg10762 (view) | Author: Nick (nickmbailey) | Date: 2016-02-22.23:04:31 |  |  
   | I think Jython is using netty's channel future incorrectly and causing a deadlock.
The netty docs say it is preferred to add asynchronous listeners rather than calling sync()/await() directly.
https://github.com/netty/netty/blob/4.0/transport/src/main/java/io/netty/channel/ChannelFuture.java#L96
Jython is doing things the incorrect way when closing sockets:
https://github.com/jythontools/jython/blob/master/Lib/_socket.py#L1059
In my twisted application running on jython I can easily cause deadlocks by using apache bench to load test the twisted web server. I think we can safely just add the rest of the shutdown code as a listener on the channel future like so:
diff --git a/Lib/_socket.py b/Lib/_socket.py
index 3b658e5..56d8f4d 100644
--- a/Lib/_socket.py
+++ b/Lib/_socket.py
@@ -1055,11 +1055,10 @@ class _realsocket(object):
             if self.channel is None:
                 return
-            try:
-                self.channel.close().sync()
-            except RejectedExecutionException:
-                # Do not care about tasks that attempt to schedule after close
-                pass
+            closeFuture = self.channel.close()
+            closeFuture.addListener(self.finishClosing)
+
+    def finishClosing(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)
If I apply that patch, I can no longer cause the deadlock. |  
   | msg10763 (view) | Author: Jim Baker (zyasoft) | Date: 2016-02-22.23:59:07 |  |  
   | Looks reasonable, although we should apply a test on the future (isSuccess()) before adding the listener. |  
   | msg10764 (view) | Author: Nick (nickmbailey) | Date: 2016-02-23.16:31:23 |  |  
   | Well the promise itself will call the listener immediately if the promise is already done. Is there another reason to check success beforehand? |  
   | msg10771 (view) | Author: Jim Baker (zyasoft) | Date: 2016-02-24.06:26:41 |  |  
   | I was attempting to justify my response to why use isSuccess() when closing this bug out when I realized:
I am wrong, the noise is test_socket is OK, compared to the alternative.
If we don't attempt to add the listener *always*, we simply have a silent race where the thread pool resource may not be cleaned up. And that's far worse.
See https://github.com/netty/netty/issues/2166 - perhaps we can tune the logging.
So latest fix is in https://hg.python.org/jython/rev/08b7720fd321 |  |
 
| Date | User | Action | Args |  | 2016-03-14 16:40:48 | zyasoft | set | status: pending -> closed |  | 2016-02-24 06:26:41 | zyasoft | set | status: open -> pending assignee: zyasoft
 resolution: fixed
 messages:
  + msg10771
 |  | 2016-02-24 03:11:47 | zyasoft | set | priority: high milestone: Jython 2.7.1
 |  | 2016-02-23 16:31:24 | nickmbailey | set | messages:
  + msg10764 |  | 2016-02-22 23:59:08 | zyasoft | set | nosy:
  + zyasoft messages:
  + msg10763
 |  | 2016-02-22 23:04:32 | nickmbailey | create |  | 
 |