[XEND] Change SrvServer to not require sockets to be non-blocking.
authorAlastair Tse <atse@xensource.com>
Thu, 18 Jan 2007 15:52:23 +0000 (15:52 +0000)
committerAlastair Tse <atse@xensource.com>
Thu, 18 Jan 2007 15:52:23 +0000 (15:52 +0000)
Set all spawned server threads to be daemonic and make sure their
sockets are closed properly using shutdown() and close(), otherwise
reload will complain about the "Address still in use."

Signed-off-by: Alastair Tse <atse@xensource.com>
tools/python/xen/util/xmlrpclib2.py
tools/python/xen/web/httpserver.py
tools/python/xen/xend/server/SrvServer.py
tools/python/xen/xend/server/XMLRPCServer.py

index 3ba1b259b1332c2f0e1feba0ff3decf471245cba..ac95d4cf39673e44875fcdb4734d92cf4e3b7a9d 100644 (file)
@@ -256,6 +256,7 @@ class UnixXMLRPCRequestHandler(XMLRPCRequestHandler):
 
 class UnixXMLRPCServer(TCPXMLRPCServer):
     address_family = socket.AF_UNIX
+    allow_address_reuse = True
 
     def __init__(self, addr, allowed, xenapi, logRequests = 1):
         mkdir.parents(os.path.dirname(addr), stat.S_IRWXU, True)
index 2326a2b875a8c2abb85cdc03d311a3abf2c20bb6..14965e418fa296c87e4a9d140ad50a0d7fd25ab4 100644 (file)
@@ -294,8 +294,6 @@ class HttpServer:
 
     backlog = 5
 
-    closed = False
-
     def __init__(self, root, interface, port=8080):
         self.root = root
         self.interface = interface
@@ -303,6 +301,7 @@ class HttpServer:
         # ready indicates when we are ready to begin accept connections
         # it should be set after a successful bind
         self.ready = False
+        self.closed = False
 
     def run(self):
         self.bind()
@@ -317,7 +316,6 @@ class HttpServer:
     def stop(self):
         self.close()
 
-
     def bind(self):
         self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         flags = fcntl.fcntl(self.socket.fileno(), fcntl.F_GETFD)
@@ -334,7 +332,10 @@ class HttpServer:
 
     def close(self):
         self.closed = True
+        self.ready = False
         try:
+            # shutdown socket explicitly to allow reuse
+            self.socket.shutdown(socket.SHUT_RDWR)
             self.socket.close()
         except:
             pass
@@ -345,6 +346,9 @@ class HttpServer:
     def getResource(self, req):
         return self.root.getRequestResource(req)
 
+    def shutdown(self):
+        self.close()
+
 
 class UnixHttpServer(HttpServer):
 
index 9810f2896e709b06c84fff55930617d74378795e..d4aae088e6c98a49bd492f6022c1ccfec86c084c 100644 (file)
@@ -65,6 +65,7 @@ class XendServers:
     def __init__(self, root):
         self.servers = []
         self.root = root
+        self.running = False
         self.cleaningUp = False
         self.reloadingConfig = False
 
@@ -79,6 +80,7 @@ class XendServers:
                 server.shutdown()
             except:
                 pass
+        self.running = False
 
     def reloadConfig(self, signum = 0, frame = None):
         log.debug("SrvServer.reloadConfig()")
@@ -107,13 +109,12 @@ class XendServers:
                 if server.ready:
                     continue
 
-                thread = Thread(target=server.run, name=server.__class__.__name__)
-                if isinstance(server, HttpServer):
-                    thread.setDaemon(True)
+                thread = Thread(target=server.run,
+                                name=server.__class__.__name__)
+                thread.setDaemon(True)
                 thread.start()
                 threads.append(thread)
 
-
             # check for when all threads have initialized themselves and then
             # close the status pipe
 
@@ -143,42 +144,27 @@ class XendServers:
                 status.close()
                 status = None
 
-            # Interruptible Thread.join - Python Bug #1167930
-            #   Replaces: for t in threads: t.join()
-            #   Reason:   The above will cause python signal handlers to be
-            #             blocked so we're not able to catch SIGTERM in any
-            #             way for cleanup
-            runningThreads = threads
-            while len(runningThreads) > 0:
-                try:
-                    for t in threads:
-                        t.join(1.0)
-                    runningThreads = [t for t in threads
-                                      if t.isAlive() and not t.isDaemon()]
-                    if self.cleaningUp and len(runningThreads) > 0:
-                        log.debug("Waiting for %s." %
-                                  [x.getName() for x in runningThreads])
-                except:
-                    pass
-
+            # loop to keep main thread alive until it receives a SIGTERM
+            self.running = True
+            while self.running:
+                time.sleep(100000000)
+                
             if self.reloadingConfig:
                 log.info("Restarting all XML-RPC and Xen-API servers...")
                 self.cleaningUp = False
                 self.reloadingConfig = False
                 xoptions.set_config()
-                new_servers = [x for x in self.servers
-                               if isinstance(x, HttpServer)]
-                self.servers = new_servers
+                self.servers = []
                 _loadConfig(self, self.root, True)
             else:
                 break
 
 def _loadConfig(servers, root, reload):
-    if not reload and xoptions.get_xend_http_server():
+    if xoptions.get_xend_http_server():
         servers.add(HttpServer(root,
                                xoptions.get_xend_address(),
                                xoptions.get_xend_port()))
-    if not reload and xoptions.get_xend_unix_server():
+    if  xoptions.get_xend_unix_server():
         path = xoptions.get_xend_unix_path()
         log.info('unix path=' + path)
         servers.add(UnixHttpServer(root, path))
index 05646fcea6946fd1b57c0b4efc0511f3105b0fcd..130da9aea8115f7f8dbcd91144e0c18482cf443f 100644 (file)
@@ -179,21 +179,24 @@ class XMLRPCServer:
         # Custom runloop so we can cleanup when exiting.
         # -----------------------------------------------------------------
         try:
-            self.server.socket.settimeout(1.0)
             while self.running:
                 self.server.handle_request()
         finally:
-            self.cleanup()
+            self.shutdown()
 
     def cleanup(self):
-        log.debug("XMLRPCServer.cleanup()")
+        log.debug('XMLRPCServer.cleanup()')
         try:
-            self.server.socket.close()
+            if hasattr(self, 'server'):
+                # shutdown socket explicitly to allow reuse
+                self.server.socket.shutdown(socket.SHUT_RDWR)
+                self.server.socket.close()
         except Exception, exn:
             log.exception(exn)
             pass
 
     def shutdown(self):
         self.running = False
-        self.ready = False
-
+        if self.ready:
+            self.ready = False
+            self.cleanup()