[pypy-commit] pypy default: merge cpyext-recursionlimit which implements Py_EnterRecursiveCall and friends
mattip
pypy.commits at gmail.com
Sat May 20 15:42:01 EDT 2017
Author: Matti Picus <matti.picus at gmail.com>
Branch:
Changeset: r91350:17fddf817604
Date: 2017-05-20 22:34 +0300
http://bitbucket.org/pypy/pypy/changeset/17fddf817604/
Log: merge cpyext-recursionlimit which implements Py_EnterRecursiveCall
and friends
diff --git a/pypy/module/cpyext/eval.py b/pypy/module/cpyext/eval.py
--- a/pypy/module/cpyext/eval.py
+++ b/pypy/module/cpyext/eval.py
@@ -1,6 +1,8 @@
from pypy.interpreter.error import oefmt
from pypy.interpreter.astcompiler import consts
from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rlib.objectmodel import we_are_translated
+from rpython.rlib.rarithmetic import widen
from pypy.module.cpyext.api import (
cpython_api, CANNOT_FAIL, CONST_STRING, FILEP, fread, feof, Py_ssize_tP,
cpython_struct, is_valid_fp)
@@ -227,4 +229,51 @@
cf.c_cf_flags = rffi.cast(rffi.INT, flags)
return result
+ at cpython_api([], rffi.INT_real, error=CANNOT_FAIL)
+def Py_GetRecursionLimit(space):
+ from pypy.module.sys.vm import getrecursionlimit
+ return space.int_w(getrecursionlimit(space))
+ at cpython_api([rffi.INT_real], lltype.Void, error=CANNOT_FAIL)
+def Py_SetRecursionLimit(space, limit):
+ from pypy.module.sys.vm import setrecursionlimit
+ setrecursionlimit(space, widen(limit))
+
+limit = 0 # for testing
+
+ at cpython_api([rffi.CCHARP], rffi.INT_real, error=1)
+def Py_EnterRecursiveCall(space, where):
+ """Marks a point where a recursive C-level call is about to be performed.
+
+ If USE_STACKCHECK is defined, this function checks if the the OS
+ stack overflowed using PyOS_CheckStack(). In this is the case, it
+ sets a MemoryError and returns a nonzero value.
+
+ The function then checks if the recursion limit is reached. If this is the
+ case, a RuntimeError is set and a nonzero value is returned.
+ Otherwise, zero is returned.
+
+ where should be a string such as " in instance check" to be
+ concatenated to the RuntimeError message caused by the recursion depth
+ limit."""
+ if not we_are_translated():
+ # XXX hack since the stack checks only work translated
+ global limit
+ limit += 1
+ if limit > 10:
+ raise oefmt(space.w_RuntimeError,
+ "maximum recursion depth exceeded%s", rffi.charp2str(where))
+ return 0
+ from rpython.rlib.rstack import stack_almost_full
+ if stack_almost_full():
+ raise oefmt(space.w_RuntimeError,
+ "maximum recursion depth exceeded%s", rffi.charp2str(where))
+ return 0
+
+ at cpython_api([], lltype.Void)
+def Py_LeaveRecursiveCall(space):
+ """Ends a Py_EnterRecursiveCall(). Must be called once for each
+ successful invocation of Py_EnterRecursiveCall()."""
+ # A NOP in PyPy
+ if not we_are_translated():
+ limit = 0
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -490,29 +490,6 @@
0 on success, -1 on failure."""
raise NotImplementedError
- at cpython_api([rffi.CCHARP], rffi.INT_real, error=1)
-def Py_EnterRecursiveCall(space, where):
- """Marks a point where a recursive C-level call is about to be performed.
-
- If USE_STACKCHECK is defined, this function checks if the the OS
- stack overflowed using PyOS_CheckStack(). In this is the case, it
- sets a MemoryError and returns a nonzero value.
-
- The function then checks if the recursion limit is reached. If this is the
- case, a RuntimeError is set and a nonzero value is returned.
- Otherwise, zero is returned.
-
- where should be a string such as " in instance check" to be
- concatenated to the RuntimeError message caused by the recursion depth
- limit."""
- raise NotImplementedError
-
- at cpython_api([], lltype.Void)
-def Py_LeaveRecursiveCall(space):
- """Ends a Py_EnterRecursiveCall(). Must be called once for each
- successful invocation of Py_EnterRecursiveCall()."""
- raise NotImplementedError
-
@cpython_api([PyFileObject], lltype.Void)
def PyFile_IncUseCount(space, p):
"""Increments the PyFileObject's internal use count to indicate
diff --git a/pypy/module/cpyext/test/test_eval.py b/pypy/module/cpyext/test/test_eval.py
--- a/pypy/module/cpyext/test/test_eval.py
+++ b/pypy/module/cpyext/test/test_eval.py
@@ -331,3 +331,30 @@
def nested_flags():
return module.get_flags()""" in ns
assert ns['nested_flags']() == (1, 0x2000) # CO_FUTURE_DIVISION
+
+ def test_recursive_function(self):
+ module = self.import_extension('foo', [
+ ("call_recursive", "METH_NOARGS",
+ """
+ int res = 0;
+ int recurse(void) {
+ if (Py_EnterRecursiveCall(" while calling recurse"))
+ return -1;
+ res ++;
+ return recurse();
+ }
+ int oldlimit = Py_GetRecursionLimit();
+ Py_SetRecursionLimit(200);
+ res = recurse();
+ Py_SetRecursionLimit(oldlimit);
+ if (PyErr_Occurred())
+ return NULL;
+ return PyLong_FromLong(res);
+ """),], prologue= ''' int recurse(void); '''
+ )
+ try:
+ res = module.call_recursive()
+ except RuntimeError as e:
+ assert 'while calling recurse' in str(e)
+ else:
+ assert False, "expected RuntimeError"
More information about the pypy-commit
mailing list