Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/cysignals/signals.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#*****************************************************************************

from cpython.object cimport PyObject
from posix.time cimport timespec

cdef extern from *:
int unlikely(int) nogil # Defined by Cython
Expand All @@ -29,6 +30,7 @@ cdef extern from "struct_signals.h":
cy_atomic_int block_sigint
const char* s
PyObject* exc_value
timespec gc_pause_until


cdef extern from "macros.h" nogil:
Expand Down
47 changes: 39 additions & 8 deletions src/cysignals/signals.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,35 @@ from cpython.ref cimport Py_XINCREF, Py_CLEAR
from cpython.exc cimport (PyErr_Occurred, PyErr_NormalizeException,
PyErr_Fetch, PyErr_Restore)
from cpython.version cimport PY_MAJOR_VERSION
from posix.time cimport clock_gettime, CLOCK_MONOTONIC

cimport cython
import sys
from gc import collect


cdef inline bint timespec_is_zero(timespec t):
return t.tv_sec == 0 and t.tv_nsec == 0


cdef inline bint timespec_less(timespec a, timespec b):
return a.tv_sec < b.tv_sec or (a.tv_sec == b.tv_sec and a.tv_nsec < b.tv_nsec)


cdef inline timespec timespec_add(timespec a, long long b):
cdef long long d = cython.cdiv(a.tv_nsec + b, 1000000000)
a.tv_sec += d
a.tv_nsec += b - d * 1000000000
if a.tv_nsec < 0:
a.tv_nsec += 1000000000
a.tv_sec -= 1
return a


cdef inline long long timespec_diff(timespec a, timespec b):
return (a.tv_sec - b.tv_sec) * <long long>1000000000 + a.tv_nsec - b.tv_nsec


# On Windows, some signals are not pre-defined.
# We define them here with values that will never occur in practice
# (to avoid compilation errors and conditional compilation).
Expand Down Expand Up @@ -355,6 +379,7 @@ def python_check_interrupt(sig, frame):
sig_check()



cdef void verify_exc_value() noexcept:
"""
Check that ``cysigs.exc_value`` is still the exception being raised.
Expand Down Expand Up @@ -396,14 +421,20 @@ cdef void verify_exc_value() noexcept:
Py_CLEAR(cysigs.exc_value)
return

# To be safe, we run the garbage collector because it may clear
# references to our exception.
try:
collect()
except Exception:
# This can happen when Python is shutting down and the gc module
# is not functional anymore.
pass
cdef timespec cur_time, finish_time
clock_gettime(CLOCK_MONOTONIC, &cur_time)
if timespec_is_zero(cysigs.gc_pause_until) or timespec_less(cysigs.gc_pause_until, cur_time):
# To be safe, we run the garbage collector because it may clear
# references to our exception.
try:
collect()
except Exception:
# This can happen when Python is shutting down and the gc module
# is not functional anymore.
pass

clock_gettime(CLOCK_MONOTONIC, &finish_time)
cysigs.gc_pause_until = timespec_add(finish_time, timespec_diff(finish_time, cur_time) * 5)

# Make sure we still have cysigs.exc_value at all; if this function was
# called again during garbage collection it might have already been set
Expand Down
5 changes: 5 additions & 0 deletions src/cysignals/struct_signals.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <setjmp.h>
#include <signal.h>
#include <Python.h>
#include <sys/time.h>


/* Choose sigjmp/longjmp variant */
Expand Down Expand Up @@ -92,6 +93,10 @@ typedef struct
* This is used by the sig_occurred function. */
PyObject* exc_value;

/* Time until calling garbage collector is allowed. Using monotonic clock.
* See https://github.com/sagemath/cysignals/issues/215. */
struct timespec gc_pause_until;

#if ENABLE_DEBUG_CYSIGNALS
int debug_level;
#endif
Expand Down
Loading