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