mirror of https://github.com/MagicStack/uvloop.git
signals: Use 'sigaction' syscall for setting up signal handlers
This commit is contained in:
parent
e7c7af4497
commit
97a64505d1
|
@ -227,6 +227,85 @@ loop.run_forever()
|
|||
class Test_UV_Signals(_TestSignal, tb.UVTestCase):
|
||||
NEW_LOOP = 'uvloop.new_event_loop()'
|
||||
|
||||
def test_signals_restore(self):
|
||||
# Test that uvloop restores signals installed with the signals
|
||||
# module after the loop is done running.
|
||||
|
||||
async def runner():
|
||||
PROG = R"""\
|
||||
import asyncio
|
||||
import uvloop
|
||||
import signal
|
||||
import time
|
||||
|
||||
srv = None
|
||||
|
||||
async def worker():
|
||||
global srv
|
||||
cb = lambda *args: None
|
||||
srv = await asyncio.start_server(cb, '127.0.0.1', 0)
|
||||
print('READY', flush=True)
|
||||
|
||||
def py_handler(signum, frame):
|
||||
print('pyhandler', flush=True)
|
||||
|
||||
def aio_handler():
|
||||
print('aiohandler', flush=True)
|
||||
loop.stop()
|
||||
|
||||
signal.signal(signal.SIGUSR1, py_handler)
|
||||
|
||||
print('step1', flush=True)
|
||||
print(input(), flush=True)
|
||||
loop = """ + self.NEW_LOOP + """
|
||||
loop.add_signal_handler(signal.SIGUSR1, aio_handler)
|
||||
asyncio.set_event_loop(loop)
|
||||
loop.create_task(worker())
|
||||
loop.run_forever()
|
||||
print('step3', flush=True)
|
||||
print(input(), flush=True)
|
||||
"""
|
||||
|
||||
proc = await asyncio.create_subprocess_exec(
|
||||
sys.executable, b'-c', PROG,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
loop=self.loop)
|
||||
|
||||
ln = await proc.stdout.readline()
|
||||
self.assertEqual(ln, b'step1\n')
|
||||
|
||||
proc.send_signal(signal.SIGUSR1)
|
||||
ln = await proc.stdout.readline()
|
||||
self.assertEqual(ln, b'pyhandler\n')
|
||||
|
||||
proc.stdin.write(b'test\n')
|
||||
ln = await proc.stdout.readline()
|
||||
self.assertEqual(ln, b'test\n')
|
||||
|
||||
ln = await proc.stdout.readline()
|
||||
self.assertEqual(ln, b'READY\n')
|
||||
|
||||
proc.send_signal(signal.SIGUSR1)
|
||||
ln = await proc.stdout.readline()
|
||||
self.assertEqual(ln, b'aiohandler\n')
|
||||
|
||||
ln = await proc.stdout.readline()
|
||||
self.assertEqual(ln, b'step3\n')
|
||||
|
||||
proc.send_signal(signal.SIGUSR1)
|
||||
ln = await proc.stdout.readline()
|
||||
self.assertEqual(ln, b'pyhandler\n')
|
||||
|
||||
proc.stdin.write(b'done\n')
|
||||
|
||||
out, err = await proc.communicate()
|
||||
self.assertEqual(out, b'done\n')
|
||||
self.assertEqual(err, b'')
|
||||
|
||||
self.loop.run_until_complete(runner())
|
||||
|
||||
|
||||
class Test_AIO_Signals(_TestSignal, tb.AIOTestCase):
|
||||
NEW_LOOP = 'asyncio.new_event_loop()'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from posix.signal cimport sigaction_t, sigaction
|
||||
from libc.signal cimport SIG_DFL, SIG_IGN, SIG_ERR, sighandler_t, signal, SIGINT
|
||||
from posix.signal cimport sigaction_t, sigaction, sigfillset
|
||||
from libc.signal cimport SIG_DFL, SIG_IGN, sighandler_t, signal, SIGINT
|
||||
|
||||
|
||||
cdef class SignalsStack:
|
||||
|
@ -22,6 +22,7 @@ cdef class SignalsStack:
|
|||
cdef restore(self):
|
||||
cdef:
|
||||
sighandler_t sig
|
||||
sigaction_t sa
|
||||
|
||||
if not self.saved:
|
||||
raise RuntimeError("SignalsStack.save() wasn't called")
|
||||
|
@ -29,9 +30,14 @@ cdef class SignalsStack:
|
|||
for i in range(MAX_SIG):
|
||||
if self.signals[i] == NULL:
|
||||
continue
|
||||
sig = signal(i, self.signals[i])
|
||||
if sig == SIG_ERR:
|
||||
raise RuntimeError("Couldn't restore signal {}".format(i))
|
||||
|
||||
memset(&sa, 0, sizeof(sa))
|
||||
if sigfillset(&sa.sa_mask):
|
||||
raise RuntimeError(
|
||||
'failed to restore signal (sigfillset failed)')
|
||||
sa.sa_handler = self.signals[i]
|
||||
if sigaction(i, &sa, NULL):
|
||||
raise convert_error(-errno.errno)
|
||||
|
||||
|
||||
cdef void __signal_handler_sigint(int sig) nogil:
|
||||
|
@ -41,11 +47,7 @@ cdef void __signal_handler_sigint(int sig) nogil:
|
|||
# Python code here -- all '.' and '[]' operators work on
|
||||
# C structs/pointers.
|
||||
|
||||
if sig != SIGINT:
|
||||
return
|
||||
|
||||
if __main_loop__ is None or __main_loop__.py_signals is None:
|
||||
# Shouldn't ever happen.
|
||||
if sig != SIGINT or __main_loop__ is None:
|
||||
return
|
||||
|
||||
if __main_loop__._executing_py_code and not __main_loop__._custom_sigint:
|
||||
|
@ -54,9 +56,16 @@ cdef void __signal_handler_sigint(int sig) nogil:
|
|||
|
||||
if __main_loop__.uv_signals is not None:
|
||||
handle = __main_loop__.uv_signals.signals[sig]
|
||||
if handle not in (SIG_DFL, SIG_IGN, SIG_ERR, NULL):
|
||||
if handle is not NULL:
|
||||
handle(sig) # void
|
||||
|
||||
|
||||
cdef void __signal_set_sigint():
|
||||
signal(SIGINT, <sighandler_t>__signal_handler_sigint)
|
||||
cdef __signal_set_sigint():
|
||||
cdef sigaction_t sa
|
||||
memset(&sa, 0, sizeof(sa))
|
||||
if sigfillset(&sa.sa_mask):
|
||||
raise RuntimeError(
|
||||
'failed to set SIGINT signal (sigfillset failed)')
|
||||
sa.sa_handler = __signal_handler_sigint
|
||||
if sigaction(SIGINT, &sa, NULL):
|
||||
raise convert_error(-errno.errno)
|
||||
|
|
Loading…
Reference in New Issue