mirror of https://github.com/MagicStack/uvloop.git
create_server() now makes a strong ref to the Server object.
Fixes #81. Also makes Server objects weak-refable.
This commit is contained in:
parent
45e89cf2ab
commit
135d060690
|
@ -6,6 +6,7 @@ import uvloop
|
|||
import ssl
|
||||
import sys
|
||||
import threading
|
||||
import weakref
|
||||
|
||||
from uvloop import _testbase as tb
|
||||
|
||||
|
@ -262,6 +263,50 @@ class _TestTCP:
|
|||
|
||||
self.loop.run_until_complete(runner())
|
||||
|
||||
def test_create_server_7(self):
|
||||
# Test that create_server() stores a hard ref to the server object
|
||||
# somewhere in the loop. In asyncio it so happens that
|
||||
# loop.sock_accept() has a reference to the server object so it
|
||||
# never gets GCed.
|
||||
|
||||
class Proto(asyncio.Protocol):
|
||||
def connection_made(self, tr):
|
||||
self.tr = tr
|
||||
self.tr.write(b'hello')
|
||||
|
||||
async def test():
|
||||
port = tb.find_free_port()
|
||||
srv = await self.loop.create_server(Proto, '127.0.0.1', port)
|
||||
wsrv = weakref.ref(srv)
|
||||
del srv
|
||||
|
||||
gc.collect()
|
||||
gc.collect()
|
||||
gc.collect()
|
||||
|
||||
s = socket.socket(socket.AF_INET)
|
||||
with s:
|
||||
s.setblocking(False)
|
||||
await self.loop.sock_connect(s, ('127.0.0.1', port))
|
||||
d = await self.loop.sock_recv(s, 100)
|
||||
self.assertEqual(d, b'hello')
|
||||
|
||||
srv = wsrv()
|
||||
srv.close()
|
||||
await srv.wait_closed()
|
||||
del srv
|
||||
|
||||
# Let all transports shutdown.
|
||||
await asyncio.sleep(0.1, loop=self.loop)
|
||||
|
||||
gc.collect()
|
||||
gc.collect()
|
||||
gc.collect()
|
||||
|
||||
self.assertIsNone(wsrv())
|
||||
|
||||
self.loop.run_until_complete(test())
|
||||
|
||||
def test_create_connection_1(self):
|
||||
CNT = 0
|
||||
TOTAL_CNT = 100
|
||||
|
|
|
@ -52,6 +52,8 @@ cdef class Loop:
|
|||
set _queued_streams
|
||||
Py_ssize_t _ready_len
|
||||
|
||||
set _servers
|
||||
|
||||
object _transports
|
||||
dict _fd_to_reader_fileobj
|
||||
dict _fd_to_writer_fileobj
|
||||
|
|
|
@ -148,6 +148,8 @@ cdef class Loop:
|
|||
# Set to True when `loop.shutdown_asyncgens` is called.
|
||||
self._asyncgens_shutdown_called = False
|
||||
|
||||
self._servers = set()
|
||||
|
||||
def __init__(self):
|
||||
self.set_debug((not sys_ignore_environment
|
||||
and bool(os_environ.get('PYTHONASYNCIODEBUG'))))
|
||||
|
@ -1509,6 +1511,7 @@ cdef class Loop:
|
|||
|
||||
server._add_server(tcp)
|
||||
|
||||
server._ref()
|
||||
return server
|
||||
|
||||
async def create_connection(self, protocol_factory, host=None, port=None, *,
|
||||
|
|
|
@ -4,9 +4,13 @@ cdef class Server:
|
|||
list _waiters
|
||||
int _active_count
|
||||
Loop _loop
|
||||
object __weakref__
|
||||
|
||||
cdef _add_server(self, UVStreamServer srv)
|
||||
cdef _wakeup(self)
|
||||
|
||||
cdef _attach(self)
|
||||
cdef _detach(self)
|
||||
|
||||
cdef _ref(self)
|
||||
cdef _unref(self)
|
||||
|
|
|
@ -27,6 +27,13 @@ cdef class Server:
|
|||
if self._active_count == 0 and self._servers is None:
|
||||
self._wakeup()
|
||||
|
||||
cdef _ref(self):
|
||||
# Keep the server object alive while it's not explicitly closed.
|
||||
self._loop._servers.add(self)
|
||||
|
||||
cdef _unref(self):
|
||||
self._loop._servers.discard(self)
|
||||
|
||||
# Public API
|
||||
|
||||
def __repr__(self):
|
||||
|
@ -40,25 +47,32 @@ cdef class Server:
|
|||
await waiter
|
||||
|
||||
def close(self):
|
||||
cdef list servers
|
||||
|
||||
if self._servers is None:
|
||||
return
|
||||
|
||||
cdef list servers = self._servers
|
||||
self._servers = None
|
||||
try:
|
||||
servers = self._servers
|
||||
self._servers = None
|
||||
|
||||
for server in servers:
|
||||
(<UVStreamServer>server)._close()
|
||||
for server in servers:
|
||||
(<UVStreamServer>server)._close()
|
||||
|
||||
if self._active_count == 0:
|
||||
self._wakeup()
|
||||
if self._active_count == 0:
|
||||
self._wakeup()
|
||||
finally:
|
||||
self._unref()
|
||||
|
||||
property sockets:
|
||||
def __get__(self):
|
||||
cdef list sockets = []
|
||||
|
||||
for server in self._servers:
|
||||
sockets.append(
|
||||
(<UVStreamServer>server)._get_socket()
|
||||
)
|
||||
# Guard against `self._servers is None`
|
||||
if self._servers:
|
||||
for server in self._servers:
|
||||
sockets.append(
|
||||
(<UVStreamServer>server)._get_socket()
|
||||
)
|
||||
|
||||
return sockets
|
||||
|
|
Loading…
Reference in New Issue