Skip to content

Commit

Permalink
workaround to the signal on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
brickgao committed Sep 6, 2016
1 parent fa2b7db commit eb9b9b7
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 42 deletions.
11 changes: 3 additions & 8 deletions uvloop/loop.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"
51 changes: 17 additions & 34 deletions uvloop/loop.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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,
Expand All @@ -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)
Expand Down Expand Up @@ -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"

Expand Down
17 changes: 17 additions & 0 deletions uvloop/os_signal_win.pxd
Original file line number Diff line number Diff line change
@@ -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)
57 changes: 57 additions & 0 deletions uvloop/os_signal_win.pyx
Original file line number Diff line number Diff line change
@@ -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 = <sighandler_t>(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)

0 comments on commit eb9b9b7

Please sign in to comment.