import socket
|
import signal
|
import warnings
|
|
from .. import _core
|
from .._util import is_main_thread
|
|
|
class WakeupSocketpair:
|
def __init__(self):
|
self.wakeup_sock, self.write_sock = socket.socketpair()
|
self.wakeup_sock.setblocking(False)
|
self.write_sock.setblocking(False)
|
# This somewhat reduces the amount of memory wasted queueing up data
|
# for wakeups. With these settings, maximum number of 1-byte sends
|
# before getting BlockingIOError:
|
# Linux 4.8: 6
|
# macOS (darwin 15.5): 1
|
# Windows 10: 525347
|
# Windows you're weird. (And on Windows setting SNDBUF to 0 makes send
|
# blocking, even on non-blocking sockets, so don't do that.)
|
self.wakeup_sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 1)
|
self.write_sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 1)
|
# On Windows this is a TCP socket so this might matter. On other
|
# platforms this fails b/c AF_UNIX sockets aren't actually TCP.
|
try:
|
self.write_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
except OSError:
|
pass
|
self.old_wakeup_fd = None
|
|
def wakeup_thread_and_signal_safe(self):
|
try:
|
self.write_sock.send(b"\x00")
|
except BlockingIOError:
|
pass
|
|
async def wait_woken(self):
|
await _core.wait_readable(self.wakeup_sock)
|
self.drain()
|
|
def drain(self):
|
try:
|
while True:
|
self.wakeup_sock.recv(2**16)
|
except BlockingIOError:
|
pass
|
|
def wakeup_on_signals(self):
|
assert self.old_wakeup_fd is None
|
if not is_main_thread():
|
return
|
fd = self.write_sock.fileno()
|
self.old_wakeup_fd = signal.set_wakeup_fd(fd, warn_on_full_buffer=False)
|
if self.old_wakeup_fd != -1:
|
warnings.warn(
|
RuntimeWarning(
|
"It looks like Trio's signal handling code might have "
|
"collided with another library you're using. If you're "
|
"running Trio in guest mode, then this might mean you "
|
"should set host_uses_signal_set_wakeup_fd=True. "
|
"Otherwise, file a bug on Trio and we'll help you figure "
|
"out what's going on."
|
)
|
)
|
|
def close(self):
|
self.wakeup_sock.close()
|
self.write_sock.close()
|
if self.old_wakeup_fd is not None:
|
signal.set_wakeup_fd(self.old_wakeup_fd)
|