[tor-commits] [stem/master] Fixing another close() deadlock issue

atagar at torproject.org atagar at torproject.org
Mon Feb 20 00:38:52 UTC 2012


commit be32e6a5017b220643ee4df4aace3d81a6acdd73
Author: Damian Johnson <atagar at torproject.org>
Date:   Sun Feb 19 16:33:42 2012 -0800

    Fixing another close() deadlock issue
    
    The previous fix narrowed the window where close() / recv() calls could trigger
    deadlock, but it didn't eliminate it. I'm adding another test that reliably
    triggered deadlock in that case and narrowing the window even more (which fixed
    the issue).
    
    I'm a little worried that this doesn't completely eliminate the issue since
    there is a theoretical race if recv() calls close after someone else calls
    close() but before they set the boolean flag. That said, I'm not sure if this
    is really an issue in practice.
---
 stem/socket.py                        |    3 +-
 test/integ/control/base_controller.py |   34 +++++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 1 deletions(-)

diff --git a/stem/socket.py b/stem/socket.py
index afea436..7f15df6 100644
--- a/stem/socket.py
+++ b/stem/socket.py
@@ -202,12 +202,13 @@ class ControlSocket:
     Shuts down the socket. If it's already closed then this is a no-op.
     """
     
+    self._handling_close = True
+    
     with self._send_lock:
       # Function is idempotent with one exception: we notify _close() if this
       # is causing our is_alive() state to change.
       
       is_change = self.is_alive()
-      self._handling_close = True
       
       if self._socket:
         # if we haven't yet established a connection then this raises an error
diff --git a/test/integ/control/base_controller.py b/test/integ/control/base_controller.py
index 4c6260d..da4cc08 100644
--- a/test/integ/control/base_controller.py
+++ b/test/integ/control/base_controller.py
@@ -4,6 +4,7 @@ Integration tests for the stem.control.BaseController class.
 
 import time
 import unittest
+import threading
 
 import stem.control
 import stem.socket
@@ -101,6 +102,39 @@ class TestBaseController(unittest.TestCase):
       response = controller.msg("GETINFO blarg")
       self.assertEquals('Unrecognized key "blarg"', str(response))
   
+  def test_msg_repeatedly(self):
+    """
+    Connects, sends a burst of messages, and closes the socket repeatedly. This
+    is a simple attempt to trigger concurrency issues.
+    """
+    
+    with test.runner.get_runner().get_tor_socket() as control_socket:
+      controller = stem.control.BaseController(control_socket)
+      
+      def run_getinfo():
+        for i in xrange(150):
+          try:
+            controller.msg("GETINFO version")
+            controller.msg("GETINFO blarg")
+            controller.msg("blarg")
+          except stem.socket.ControllerError:
+            pass
+      
+      message_threads = []
+      
+      for i in xrange(5):
+        msg_thread = threading.Thread(target = run_getinfo)
+        message_threads.append(msg_thread)
+        msg_thread.setDaemon(True)
+        msg_thread.start()
+      
+      for i in xrange(100):
+        controller.connect()
+        controller.close()
+      
+      for msg_thread in message_threads:
+        msg_thread.join()
+  
   def test_status_notifications(self):
     """
     Checks basic functionality of the add_status_listener() and



More information about the tor-commits mailing list