Much better fix for problem with proxies being started and stopped quickly.

Override SocketServer methods and add additional locking so we can wait
for the server thread to finish starting up.

BUG=chromium-os:20150, chromium-os:16574
TEST=Cherry-picked from TOT to this branch

(cherry picked from commit ce442072422a7fdf758817c82ab2cc06bd8af910)
(cherry picked from commit a2c4fde0ce48bea77698d545032c2b5ee9e75dda)

Change-Id: If3468d4b0aa4a12ddd9d11bc2962bd97c1f2b723
Reviewed-on: http://gerrit.chromium.org/gerrit/7378
Reviewed-by: Don Garrett <dgarrett@chromium.org>
Tested-by: David James <davidjames@chromium.org>
diff --git a/au_test_harness/cros_test_proxy.py b/au_test_harness/cros_test_proxy.py
index 0b37286..fc3f3e7 100644
--- a/au_test_harness/cros_test_proxy.py
+++ b/au_test_harness/cros_test_proxy.py
@@ -10,6 +10,7 @@
 import socket
 import SocketServer
 import threading
+import time
 
 class Filter(object):
   """Base class for data filters.
@@ -104,6 +105,12 @@
     self.port_out = port_out
     self.filter = filter
 
+    # Used to coordinate startup/shutdown in a new thread.
+    self.__is_started = threading.Event()
+    self.__is_shut_down = threading.Event()
+    self.__serving = False
+
+
     try:
         SocketServer.TCPServer.__init__(self,
                                         ('', port_in),
@@ -112,10 +119,54 @@
       os.system('sudo netstat -l --tcp -n -p')
       raise
 
+
   def serve_forever_in_thread(self):
     """Helper method to start the server in a new background thread."""
     server_thread = threading.Thread(target=self.serve_forever)
     server_thread.setDaemon(True)
     server_thread.start()
 
+    # Wait until the server is started, bug chromium-os:16574
+    self.__is_started.wait()
+
     return server_thread
+
+  # ==========================
+
+  # Override of the version of this method from SocketServer.
+  # It's duplicated, other than adding __is_started event.
+  # Bug chromium-os:16574
+  def serve_forever(self, poll_interval=0.5):
+      """Handle one request at a time until shutdown.
+
+      Polls for shutdown every poll_interval seconds. Ignores
+      self.timeout. If you need to do periodic tasks, do them in
+      another thread.
+      """
+      self.__serving = True
+      self.__is_shut_down.clear()
+      self.__is_started.set()
+
+      while self.__serving:
+          # XXX: Consider using another file descriptor or
+          # connecting to the socket to wake this up instead of
+          # polling. Polling reduces our responsiveness to a
+          # shutdown request and wastes cpu at all other times.
+          r, w, e = select.select([self], [], [], poll_interval)
+          if r:
+              self._handle_request_noblock()
+      self.__is_started.clear()
+      self.__is_shut_down.set()
+
+  # Duplicate override of the version of this method from SocketServer so
+  # that we can access the same __ variables as serve_forever.
+  # Bug chromium-os:16574
+  def shutdown(self):
+      """Stops the serve_forever loop.
+
+      Blocks until the loop has finished. This must be called while
+      serve_forever() is running in another thread, or it will
+      deadlock.
+      """
+      self.__serving = False
+      self.__is_shut_down.wait()