Skip to content

Throttle garbage collector frequency in sig_occurred #227

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions src/cysignals/signals.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ cdef extern from "struct_signals.h":
cy_atomic_int block_sigint
const char* s
PyObject* exc_value
double gc_pause_until


cdef extern from "macros.h" nogil:
Expand Down
22 changes: 14 additions & 8 deletions src/cysignals/signals.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ 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
import time

cimport cython
import sys
Expand Down Expand Up @@ -396,14 +397,19 @@ 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 double cur_time = time.perf_counter(), finish_time
if cysigs.gc_pause_until == 0 or 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

finish_time = time.perf_counter()
cysigs.gc_pause_until = finish_time + (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 Python time.perf_counter.
* See https://github.com/sagemath/cysignals/issues/215. */
double gc_pause_until;

#if ENABLE_DEBUG_CYSIGNALS
int debug_level;
#endif
Expand Down
4 changes: 4 additions & 0 deletions src/cysignals/tests.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,8 @@ def test_sig_occurred_finally():
"""
TESTS::

>>> from time import sleep
>>> sleep(0.5) # see PR 227
>>> from cysignals.tests import *
>>> test_sig_occurred_finally()
No current exception
Expand Down Expand Up @@ -1022,6 +1024,8 @@ def test_sig_occurred_dealloc_in_gc():
>>> l = [DeallocDebug(), e]
>>> l.append(l)
>>> gc.disable()
>>> from time import sleep
>>> sleep(0.5) # see PR 227
>>> try:
... del l, e
... print_sig_occurred()
Expand Down
Loading