Commit 2ea5a374 authored by Denis Bilenko's avatar Denis Bilenko

baseserver: maintain 'started' property rather than relying on subclasses to implement it.

With this change server.started always returns True after start() before stop() (or kill()).

Previously it could be False occassionally, because StreamServer could stop accepting for a while in presence of errors and StreamServer.started was defined as "whether the server is currently accepting".

Also, in StreamServer.kill remove link installed on pool's semaphore to avoid a GC cycle.
parent 9b8a43ea
......@@ -43,6 +43,7 @@ class BaseServer(object):
self.set_listener(listener, backlog=backlog)
self.set_spawn(spawn)
self.set_handle(handle)
self.started = None
def set_listener(self, listener, backlog=None):
if hasattr(listener, 'accept'):
......@@ -126,7 +127,6 @@ class BaseServer(object):
It is not supposed to be called by the user, it is called by :meth:`start` before starting
the accept loop."""
assert not self.started, '%s already started' % self.__class__.__name__
if not hasattr(self, 'socket'):
self.socket = _tcp_listener(self.address, backlog=self.backlog, reuse_addr=self.reuse_addr)
self.address = self.socket.getsockname()
......@@ -137,7 +137,9 @@ class BaseServer(object):
If an address was provided in the constructor, then also create a socket, bind it and put it into the listening mode.
"""
assert not self.started, '%s already started' % self.__class__.__name__
self.pre_start()
self.started = True
try:
self.start_accepting()
except:
......@@ -146,13 +148,16 @@ class BaseServer(object):
def kill(self):
"""Close the listener socket and stop accepting."""
self.stop_accepting()
self.started = False
try:
self.socket.close()
except Exception:
pass
self.__dict__.pop('socket', None)
self.__dict__.pop('handle', None)
self.stop_accepting()
finally:
try:
self.socket.close()
except Exception:
pass
self.__dict__.pop('socket', None)
self.__dict__.pop('handle', None)
def stop(self, timeout=None):
"""Stop accepting the connections and close the listening socket.
......
......@@ -20,10 +20,6 @@ class HTTPServer(BaseServer):
if default_response_headers != 'default':
self.default_response_headers = default_response_headers
@property
def started(self):
return self.http is not None
def _on_request(self, request):
spawn = self._spawn
if spawn is None:
......
......@@ -67,29 +67,32 @@ class StreamServer(BaseServer):
def set_spawn(self, spawn):
BaseServer.set_spawn(self, spawn)
if self.pool is not None:
self.pool._semaphore.rawlink(self._start_accepting)
self.pool._semaphore.rawlink(self._start_accepting_if_started)
def set_handle(self, handle):
BaseServer.set_handle(self, handle)
def kill(self):
try:
BaseServer.kill(self)
finally:
self.__dict__.pop('_handle', None)
pool = getattr(self, 'pool', None)
if pool is not None:
pool._semaphore.unlink(self._start_accepting_if_started)
def pre_start(self):
BaseServer.pre_start(self)
# make SSL work:
if self.ssl_enabled:
self._handle = self.wrap_socket_and_handle
else:
self._handle = self.handle
@property
def started(self):
return self._accept_event is not None or self._start_accepting_timer is not None
def start_accepting(self):
if self._accept_event is None:
self._accept_event = core.read_event(self.socket.fileno(), self._do_accept, persist=True)
def _start_accepting(self, _event):
if self._accept_event is None:
if 'socket' not in self.__dict__:
return
self._accept_event = core.read_event(self.socket.fileno(), self._do_accept, persist=True)
def _start_accepting_if_started(self, _event=None):
if self.started:
self.start_accepting()
def stop_accepting(self):
if self._accept_event is not None:
......
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