From 112d240dcbcf5c1e79ccd94988441c74c6fcd1ab Mon Sep 17 00:00:00 2001
From: Guido Trotter <ultrotter@google.com>
Date: Wed, 19 Aug 2009 12:20:11 +0200
Subject: [PATCH] Convert the http server/mainloop to asyncore

We can avoid most of the Mainloop.Run() code if we use asyncore
for delivering I/O events, and just concentrate on what's missing in
asyncore: singnal handling and timers. This way confd can be ported to
use Mainloop as well.

Signed-off-by: Guido Trotter <ultrotter@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>
---
 lib/daemon.py      | 41 ++---------------------------------------
 lib/http/server.py | 13 +++++++------
 2 files changed, 9 insertions(+), 45 deletions(-)

diff --git a/lib/daemon.py b/lib/daemon.py
index 6799395d9..e0ab16cb4 100644
--- a/lib/daemon.py
+++ b/lib/daemon.py
@@ -22,6 +22,7 @@
 """Module with helper classes and functions for daemons"""
 
 
+import asyncore
 import os
 import select
 import signal
@@ -40,9 +41,7 @@ class Mainloop(object):
     """Constructs a new Mainloop instance.
 
     """
-    self._io_wait = {}
     self._signal_wait = []
-    self._poller = select.poll()
 
   @utils.SignalHandled([signal.SIGCHLD])
   @utils.SignalHandled([signal.SIGTERM])
@@ -66,22 +65,7 @@ class Mainloop(object):
       if stop_on_empty and not (self._io_wait):
         break
 
-      # Wait for I/O events
-      try:
-        io_events = self._poller.poll(None)
-      except select.error, err:
-        # EINTR can happen when signals are sent
-        if err.args and err.args[0] in (errno.EINTR,):
-          io_events = None
-        else:
-          raise
-
-      if io_events:
-        # Check for I/O events
-        for (evfd, evcond) in io_events:
-          owner = self._io_wait.get(evfd, None)
-          if owner:
-            owner.OnIO(evfd, evcond)
+      asyncore.loop(timeout=5, count=1, use_poll=True)
 
       # Check whether a signal was raised
       for sig in signal_handlers:
@@ -101,27 +85,6 @@ class Mainloop(object):
     for owner in self._signal_wait:
       owner.OnSignal(signal.SIGCHLD)
 
-  def RegisterIO(self, owner, fd, condition):
-    """Registers a receiver for I/O notifications
-
-    The receiver must support a "OnIO(self, fd, conditions)" function.
-
-    @type owner: instance
-    @param owner: Receiver
-    @type fd: int
-    @param fd: File descriptor
-    @type condition: int
-    @param condition: ORed field of conditions to be notified
-                      (see select module)
-
-    """
-    # select.Poller also supports file() like objects, but we don't.
-    assert isinstance(fd, (int, long)), \
-      "Only integers are supported for file descriptors"
-
-    self._io_wait[fd] = owner
-    self._poller.register(fd, condition)
-
   def RegisterSignal(self, owner):
     """Registers a receiver for signal notifications
 
diff --git a/lib/http/server.py b/lib/http/server.py
index 0afdcd00d..b3e5b787a 100644
--- a/lib/http/server.py
+++ b/lib/http/server.py
@@ -30,6 +30,7 @@ import select
 import socket
 import time
 import signal
+import asyncore
 
 from ganeti import http
 
@@ -415,7 +416,7 @@ class HttpServerRequestExecutor(object):
     """
     return self.error_message_format % values
 
-class HttpServer(http.HttpBase):
+class HttpServer(http.HttpBase, asyncore.dispatcher):
   """Generic HTTP server class
 
   Users of this class must subclass it and override the HandleRequest function.
@@ -445,6 +446,7 @@ class HttpServer(http.HttpBase):
 
     """
     http.HttpBase.__init__(self)
+    asyncore.dispatcher.__init__(self)
 
     if request_executor_class is None:
       self.request_executor = HttpServerRequestExecutor
@@ -461,8 +463,8 @@ class HttpServer(http.HttpBase):
     self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
 
     self._children = []
-
-    mainloop.RegisterIO(self, self.socket.fileno(), select.POLLIN)
+    self.set_socket(self.socket)
+    self.accepting = True
     mainloop.RegisterSignal(self)
 
   def Start(self):
@@ -472,9 +474,8 @@ class HttpServer(http.HttpBase):
   def Stop(self):
     self.socket.close()
 
-  def OnIO(self, fd, condition):
-    if condition & select.POLLIN:
-      self._IncomingConnection()
+  def handle_accept(self):
+    self._IncomingConnection()
 
   def OnSignal(self, signum):
     if signum == signal.SIGCHLD:
-- 
GitLab