Commit 112d240d authored by Guido Trotter's avatar Guido Trotter
Browse files

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: default avatarGuido Trotter <ultrotter@google.com>
Reviewed-by: default avatarIustin Pop <iustin@google.com>
parent a5bca3e9
......@@ -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
......
......@@ -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:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment