From eb9b9b7881fb1950e61033c3ba3934daf0a0c7e0 Mon Sep 17 00:00:00 2001 From: brickgao Date: Wed, 7 Sep 2016 01:35:13 +0800 Subject: [PATCH] workaround to the signal on Windows --- uvloop/loop.pxd | 11 +++----- uvloop/loop.pyx | 51 ++++++++++++----------------------- uvloop/os_signal_win.pxd | 17 ++++++++++++ uvloop/os_signal_win.pyx | 57 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 42 deletions(-) create mode 100644 uvloop/os_signal_win.pxd create mode 100644 uvloop/os_signal_win.pyx diff --git a/uvloop/loop.pxd b/uvloop/loop.pxd index b71f03ec..b04994f9 100644 --- a/uvloop/loop.pxd +++ b/uvloop/loop.pxd @@ -47,12 +47,8 @@ cdef class Loop: bint _thread_is_main bint _sigint_check - IF UNAME_SYSNAME == "Windows": - # TODO(iceboy): Signal equivalence on windows? - pass - ELSE: - SignalsStack py_signals - SignalsStack uv_signals + SignalsStack py_signals + SignalsStack uv_signals bint _executing_py_code object _task_factory @@ -207,7 +203,6 @@ include "handles/udp.pxd" include "server.pxd" IF UNAME_SYSNAME == "Windows": - # TODO(iceboy): Signal equivalence on windows? - pass + include "os_signal_win.pxd" ELSE: include "os_signal.pxd" diff --git a/uvloop/loop.pyx b/uvloop/loop.pyx index 052f25a2..afaf43e4 100644 --- a/uvloop/loop.pyx +++ b/uvloop/loop.pyx @@ -73,18 +73,14 @@ cdef class Loop: self._timers = set() self._polls = dict() - IF UNAME_SYSNAME == "Windows": - # TODO(iceboy): Signal equivalence on windows? - pass - ELSE: - if MAIN_THREAD_ID == PyThread_get_thread_ident(): # XXX - self.py_signals = SignalsStack() - self.uv_signals = SignalsStack() + if MAIN_THREAD_ID == PyThread_get_thread_ident(): # XXX + self.py_signals = SignalsStack() + self.uv_signals = SignalsStack() - self.py_signals.save() - else: - self.py_signals = None - self.uv_signals = None + self.py_signals.save() + else: + self.py_signals = None + self.uv_signals = None self._executing_py_code = 0 @@ -223,12 +219,8 @@ cdef class Loop: self._stop(SystemExit()) cdef _check_sigint(self): - IF UNAME_SYSNAME == "Windows": - # TODO(iceboy): __signal_set_sigint() on windows? - pass - ELSE: - self.uv_signals.save() - __signal_set_sigint() + self.uv_signals.save() + __signal_set_sigint() cdef _on_idle(self): cdef: @@ -290,13 +282,9 @@ cdef class Loop: cdef __run(self, uv.uv_run_mode mode): global __main_loop__ - IF UNAME_SYSNAME == "Windows": - # TODO(iceboy): Signal equivalence on windows? - pass - ELSE: - if self.py_signals is not None: - # self.py_signals is not None only for the main thread - __main_loop__ = self + if self.py_signals is not None: + # self.py_signals is not None only for the main thread + __main_loop__ = self self._executing_py_code = 0 # Although every UVHandle holds a reference to the loop, @@ -309,14 +297,10 @@ cdef class Loop: Py_DECREF(self) self._executing_py_code = 1 - IF UNAME_SYSNAME == "Windows": - # TODO(iceboy): Signal equivalence on windows? - pass - ELSE: - if self.py_signals is not None: - # self.py_signals is not None only for the main thread - self.py_signals.restore() - __main_loop__ = None + if self.py_signals is not None: + # self.py_signals is not None only for the main thread + self.py_signals.restore() + __main_loop__ = None if err < 0: raise convert_error(err) @@ -2409,8 +2393,7 @@ include "handles/udp.pyx" include "server.pyx" IF UNAME_SYSNAME == "Windows": - # TODO(iceboy): Signal equivalence on windows? - pass + include "os_signal_win.pyx" ELSE: include "os_signal.pyx" diff --git a/uvloop/os_signal_win.pxd b/uvloop/os_signal_win.pxd new file mode 100644 index 00000000..5694aa12 --- /dev/null +++ b/uvloop/os_signal_win.pxd @@ -0,0 +1,17 @@ +from libc.signal cimport sighandler_t + + +cdef extern from "Python.h": + ctypedef void (*PyOS_sighandler_t)(int) + + PyOS_sighandler_t PyOS_getsig(int) + PyOS_sighandler_t PyOS_setsig(int, PyOS_sighandler_t) + + +cdef class SignalsStack: + cdef: + sighandler_t[MAX_SIG] signals + bint saved + + cdef save(self) + cdef restore(self) diff --git a/uvloop/os_signal_win.pyx b/uvloop/os_signal_win.pyx new file mode 100644 index 00000000..5f08824c --- /dev/null +++ b/uvloop/os_signal_win.pyx @@ -0,0 +1,57 @@ +from libc.signal cimport SIG_DFL, SIG_IGN, SIG_ERR, sighandler_t, signal, SIGINT + + +cdef class SignalsStack: + def __cinit__(self): + self.saved = 0 + for i in range(MAX_SIG): + self.signals[i] = NULL + + cdef save(self): + cdef sighandler_t handler + + for i in range(MAX_SIG): + handler = (PyOS_getsig(i)) + if handler != SIG_ERR: + self.signals[i] = handler + + self.saved = 1 + + cdef restore(self): + cdef: + sighandler_t sig + + if not self.saved: + raise RuntimeError("SignalsStack.save() wasn't called") + + for i in range(MAX_SIG): + if self.signals[i] == NULL: + continue + + if PyOS_setsig(i, self.signals[i]) == SIG_ERR: + raise convert_error(-errno.errno) + + +cdef void __signal_handler_sigint(int sig) nogil: + cdef sighandler_t handle + + # We can run this method without GIL because there is no + # Python code here -- all '.' and '[]' operators work on + # C structs/pointers. + + if sig != SIGINT or __main_loop__ is None: + return + + if __main_loop__._executing_py_code and not __main_loop__._custom_sigint: + PyErr_SetInterrupt() # void + return + + if __main_loop__.uv_signals is not None: + handle = __main_loop__.uv_signals.signals[sig] + if handle is not NULL: + handle(sig) # void + + +cdef __signal_set_sigint(): + if PyOS_setsig(SIGINT, __signal_handler_sigint) == SIG_ERR: + raise convert_error(-errno.errno)