Rev 6058: Ensures that the connection thread is detached from the server thread before handling the connection. in file:///home/vila/src/bzr/bugs/869366-test-server-race/

Vincent Ladeuil v.ladeuil+lp at free.fr
Wed Nov 9 16:05:52 UTC 2011


At file:///home/vila/src/bzr/bugs/869366-test-server-race/

------------------------------------------------------------
revno: 6058
revision-id: v.ladeuil+lp at free.fr-20111109160552-qqa88x55f70o4yh8
parent: v.ladeuil+lp at free.fr-20111010102716-b8vgjpvzg3mx8w7a
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: 869366-test-server-race
timestamp: Wed 2011-11-09 17:05:52 +0100
message:
  Ensures that the connection thread is detached from the server thread before handling the connection.
-------------- next part --------------
=== modified file 'bzrlib/tests/test_server.py'
--- a/bzrlib/tests/test_server.py	2011-10-07 14:48:59 +0000
+++ b/bzrlib/tests/test_server.py	2011-11-09 16:05:52 +0000
@@ -421,12 +421,15 @@
     def get_request (self):
         """Get the request and client address from the socket."""
         sock, addr = TestingTCPServerMixin.get_request(self)
-        # The thread is not create yet, it will be updated in process_request
+        # The thread is not created yet, it will be updated in process_request
         self.clients.append((sock, addr, None))
         return sock, addr
 
-    def process_request_thread(self, started, stopped, request, client_address):
+    def process_request_thread(self, started, detached, stopped,
+                               request, client_address):
         started.set()
+        # We will be on our own once the server tells us we're detached
+        detached.wait()
         SocketServer.ThreadingTCPServer.process_request_thread(
             self, request, client_address)
         self.close_request(request)
@@ -435,12 +438,13 @@
     def process_request(self, request, client_address):
         """Start a new thread to process the request."""
         started = threading.Event()
+        detached = threading.Event()
         stopped = threading.Event()
         t = TestThread(
             sync_event=stopped,
             name='%s -> %s' % (client_address, self.server_address),
             target = self.process_request_thread,
-            args = (started, stopped, request, client_address))
+            args = (started, detached, stopped, request, client_address))
         # Update the client description
         self.clients.pop()
         self.clients.append((request, client_address, t))
@@ -449,12 +453,12 @@
         t.set_ignored_exceptions(self.ignored_exceptions)
         t.start()
         started.wait()
-        if debug_threads():
-            sys.stderr.write('Client thread %s started\n' % (t.name,))
         # If an exception occured during the thread start, it will get raised.
-        # In rare cases, an exception raised during the request processing may
-        # also get caught here (see http://pad.lv/869366)
         t.pending_exception()
+        if debug_threads():
+            sys.stderr.write('Client thread %s started\n' % (t.name,))
+        # Tell the thread, it's now on its own for exception handling.
+        detached.set()
 
     # The following methods are called by the main thread
 

=== modified file 'bzrlib/tests/test_test_server.py'
--- a/bzrlib/tests/test_test_server.py	2011-10-10 10:27:16 +0000
+++ b/bzrlib/tests/test_test_server.py	2011-11-09 16:05:52 +0000
@@ -203,20 +203,12 @@
         # Check that the connection thread did catch the exception,
         # http://pad.lv/869366 was wrongly checking the server thread which
         # works for TestingTCPServer where the connection is handled in the
-        # same thread than the server one but is racy for
-        # TestingThreadingTCPServer where the server thread may be in a
-        # blocking accept() call (or not).
-        try:
-            self.connection_thread.pending_exception()
-        except FailToRespond:
-            # Great, the test succeeded
-            pass
-        else:
-            # If the exception is not in the connection thread anymore, it's in
-            # the server's one. 
-            server.server.stopped.wait()
-            # The exception is available now
-            self.assertRaises(FailToRespond, server.pending_exception)
+        # same thread than the server one but was racy for
+        # TestingThreadingTCPServer. Since we the connection thread detaches
+        # itself before handling the request, we are guaranteed that the
+        # exception won't leak into the server thread anymore.
+        self.assertRaises(FailToRespond,
+                          self.connection_thread.pending_exception)
 
     def test_exception_swallowed_while_serving(self):
         # We need to ensure the exception has been caught



More information about the bazaar-commits mailing list