|
|
|
@ -17,12 +17,22 @@ import socket |
|
|
|
|
cdef gpr_timespec _GPR_INF_FUTURE = gpr_inf_future(GPR_CLOCK_REALTIME) |
|
|
|
|
cdef float _POLL_AWAKE_INTERVAL_S = 0.2 |
|
|
|
|
|
|
|
|
|
cdef bint _no_fd_monitoring = False |
|
|
|
|
# This bool indicates if the event loop impl can monitor a given fd, or has |
|
|
|
|
# loop.add_reader method. |
|
|
|
|
cdef bint _has_fd_monitoring = True |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IF UNAME_SYSNAME == "Windows": |
|
|
|
|
cdef void _unified_socket_write(int fd) nogil: |
|
|
|
|
win_socket_send(<WIN_SOCKET>fd, b"1", 1, 0) |
|
|
|
|
|
|
|
|
|
# If the event loop policy is Proactor, then immediately turn on fall back |
|
|
|
|
# mode. |
|
|
|
|
if asyncio.get_event_loop_policy() == asyncio.WindowsProactorEventLoopPolicy: |
|
|
|
|
_has_fd_monitoring = False |
|
|
|
|
elif asyncio.get_event_loop_policy() == asyncio.DefaultEventLoopPolicy: |
|
|
|
|
if sys.version_info >= (3, 8, 0): |
|
|
|
|
_has_fd_monitoring = False |
|
|
|
|
ELSE: |
|
|
|
|
from posix cimport unistd |
|
|
|
|
|
|
|
|
@ -43,6 +53,7 @@ cdef class BaseCompletionQueue: |
|
|
|
|
cdef class _BoundEventLoop: |
|
|
|
|
|
|
|
|
|
def __cinit__(self, object loop, object read_socket, object handler): |
|
|
|
|
global _has_fd_monitoring |
|
|
|
|
self.loop = loop |
|
|
|
|
self.read_socket = read_socket |
|
|
|
|
reader_function = functools.partial( |
|
|
|
@ -53,14 +64,18 @@ cdef class _BoundEventLoop: |
|
|
|
|
# support is available or not. Checking the event loop policy is not |
|
|
|
|
# good enough. The application can has its own loop implementation, or |
|
|
|
|
# uses different types of event loops (e.g., 1 Proactor, 3 Selectors). |
|
|
|
|
try: |
|
|
|
|
self.loop.add_reader(self.read_socket, reader_function) |
|
|
|
|
except NotImplementedError: |
|
|
|
|
_no_fd_monitoring = True |
|
|
|
|
if _has_fd_monitoring: |
|
|
|
|
try: |
|
|
|
|
self.loop.add_reader(self.read_socket, reader_function) |
|
|
|
|
self._has_reader = True |
|
|
|
|
except NotImplementedError: |
|
|
|
|
_has_fd_monitoring = False |
|
|
|
|
self._has_reader = False |
|
|
|
|
|
|
|
|
|
def close(self): |
|
|
|
|
if self.loop: |
|
|
|
|
self.loop.remove_reader(self.read_socket) |
|
|
|
|
if self._has_reader: |
|
|
|
|
self.loop.remove_reader(self.read_socket) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cdef class PollerCompletionQueue(BaseCompletionQueue): |
|
|
|
@ -106,15 +121,14 @@ cdef class PollerCompletionQueue(BaseCompletionQueue): |
|
|
|
|
self._queue_mutex.lock() |
|
|
|
|
self._queue.push(event) |
|
|
|
|
self._queue_mutex.unlock() |
|
|
|
|
if not _no_fd_monitoring: |
|
|
|
|
if _has_fd_monitoring: |
|
|
|
|
_unified_socket_write(self._write_fd) |
|
|
|
|
else: |
|
|
|
|
with gil: |
|
|
|
|
# Event loops can be paused or killed at any time. The |
|
|
|
|
# most robust way to make sure someone is polling is |
|
|
|
|
# awaking all loops up. |
|
|
|
|
for loop in self._loops: |
|
|
|
|
self._handle_events(loop) |
|
|
|
|
# Event loops can be paused or killed at any time. So, |
|
|
|
|
# instead of deligate to any thread, the polling thread |
|
|
|
|
# should handle the distribution of the event. |
|
|
|
|
self._handle_events(None) |
|
|
|
|
|
|
|
|
|
def _poll_wrapper(self): |
|
|
|
|
with nogil: |
|
|
|
@ -136,7 +150,10 @@ cdef class PollerCompletionQueue(BaseCompletionQueue): |
|
|
|
|
self._write_socket.close() |
|
|
|
|
|
|
|
|
|
def _handle_events(self, object context_loop): |
|
|
|
|
cdef bytes data = self._read_socket.recv(1) |
|
|
|
|
cdef bytes data |
|
|
|
|
if _has_fd_monitoring: |
|
|
|
|
# If fd monitoring is working, clean the socket without blocking. |
|
|
|
|
data = self._read_socket.recv(1) |
|
|
|
|
cdef grpc_event event |
|
|
|
|
cdef CallbackContext *context |
|
|
|
|
|
|
|
|
|