# coerced_self ExprNode or None used internally
# wrapper_call bool used internally
# has_optional_args bool used internally
+ # nogil bool used internally
subexprs = ['self', 'coerced_self', 'function', 'args', 'arg_tuple']
elif func_type.exception_value is not None \
or func_type.exception_check:
self.is_temp = 1
- # C++ exception handler
+ # Called in 'nogil' context?
self.nogil = env.nogil
+ if (self.nogil and
+ func_type.exception_check and
+ func_type.exception_check != '+'):
+ env.use_utility_code(pyerr_occurred_withgil_utility_code)
+ # C++ exception handler
if func_type.exception_check == '+':
if func_type.exception_value is None:
env.use_utility_code(cpp_exception_utility_code)
if exc_val is not None:
exc_checks.append("%s == %s" % (self.result(), exc_val))
if exc_check:
- exc_checks.append("PyErr_Occurred()")
+ if self.nogil:
+ exc_checks.append("__Pyx_ErrOccurredWithGIL()")
+ else:
+ exc_checks.append("PyErr_Occurred()")
if self.is_temp or exc_checks:
rhs = self.c_call_code()
if self.result():
impl = ""
)
+pyerr_occurred_withgil_utility_code= UtilityCode(
+proto = """
+static CYTHON_INLINE int __Pyx_ErrOccurredWithGIL(void); /* proto */
+""",
+impl = """
+static CYTHON_INLINE int __Pyx_ErrOccurredWithGIL(void) {
+ int err;
+ #ifdef WITH_THREAD
+ PyGILState_STATE _save = PyGILState_Ensure();
+ #endif
+ err = !!PyErr_Occurred();
+ #ifdef WITH_THREAD
+ PyGILState_Release(_save);
+ #endif
+ return err;
+}
+"""
+)
+
#------------------------------------------------------------------------------------
raise_noneattr_error_utility_code = UtilityCode(
def generate_execution_code(self, code):
code.mark_pos(self.pos)
+ code.putln("{")
if self.state == 'gil':
code.putln("#ifdef WITH_THREAD")
- code.putln("{ PyGILState_STATE _save = PyGILState_Ensure();")
+ code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
code.putln("#endif")
else:
- code.putln("{ PyThreadState *_save;")
+ code.putln("#ifdef WITH_THREAD")
+ code.putln("PyThreadState *_save;")
+ code.putln("#endif")
code.putln("Py_UNBLOCK_THREADS")
TryFinallyStatNode.generate_execution_code(self, code)
code.putln("}")
def generate_execution_code(self, code):
if self.state == 'gil':
code.putln("#ifdef WITH_THREAD")
- code.putln("PyGILState_Release(_save); }")
+ code.putln("PyGILState_Release(_save);")
code.putln("#endif")
else:
code.putln("Py_BLOCK_THREADS")
--- /dev/null
+cdef void foo(int i) except * with gil:
+ if i != 0: raise ValueError
+
+cdef int bar(int i) except? -1 with gil:
+ if i != 0: raise ValueError
+ return 0
+
+cdef int spam(int i) except? -1 with gil:
+ if i != 0: raise TypeError
+ return -1
+
+def test_foo():
+ """
+ >>> test_foo()
+ """
+ #
+ foo(0)
+ foo(0)
+ with nogil:
+ foo(0)
+ foo(0)
+ #
+ try:
+ with nogil:
+ foo(0)
+ finally:
+ pass
+ #
+ try:
+ with nogil:
+ foo(0)
+ with nogil:
+ foo(0)
+ finally:
+ pass
+ #
+ try:
+ with nogil:
+ foo(0)
+ with nogil:
+ foo(1)
+ except:
+ with nogil:
+ foo(0)
+ finally:
+ with nogil:
+ foo(0)
+ pass
+ #
+ try:
+ with nogil:
+ foo(0)
+ foo(0)
+ finally:
+ pass
+ #
+ try:
+ with nogil:
+ foo(0)
+ foo(1)
+ except:
+ with nogil:
+ foo(0)
+ finally:
+ with nogil:
+ foo(0)
+ pass
+ #
+ try:
+ with nogil:
+ foo(0)
+ try:
+ with nogil:
+ foo(1)
+ except:
+ with nogil:
+ foo(1)
+ finally:
+ with nogil:
+ foo(0)
+ pass
+ except:
+ with nogil:
+ foo(0)
+ finally:
+ with nogil:
+ foo(0)
+ pass
+ #
+ try:
+ with nogil:
+ foo(0)
+ try:
+ with nogil:
+ foo(1)
+ except:
+ with nogil:
+ foo(1)
+ finally:
+ with nogil:
+ foo(1)
+ pass
+ except:
+ with nogil:
+ foo(0)
+ finally:
+ with nogil:
+ foo(0)
+ pass
+ #
+
+def test_bar():
+ """
+ >>> test_bar()
+ """
+ #
+ bar(0)
+ bar(0)
+ with nogil:
+ bar(0)
+ bar(0)
+ #
+ try:
+ with nogil:
+ bar(0)
+ finally:
+ pass
+ #
+ try:
+ with nogil:
+ bar(0)
+ with nogil:
+ bar(0)
+ finally:
+ pass
+ #
+ try:
+ with nogil:
+ bar(0)
+ with nogil:
+ bar(1)
+ except ValueError:
+ with nogil:
+ bar(0)
+ finally:
+ with nogil:
+ bar(0)
+ pass
+ #
+ try:
+ with nogil:
+ bar(0)
+ bar(0)
+ finally:
+ pass
+ #
+ try:
+ with nogil:
+ bar(0)
+ bar(1)
+ except ValueError:
+ with nogil:
+ bar(0)
+ finally:
+ with nogil:
+ bar(0)
+ pass
+ #
+ try:
+ with nogil:
+ bar(0)
+ try:
+ with nogil:
+ bar(1)
+ except ValueError:
+ with nogil:
+ bar(1)
+ finally:
+ with nogil:
+ bar(0)
+ pass
+ except ValueError:
+ with nogil:
+ bar(0)
+ finally:
+ with nogil:
+ bar(0)
+ pass
+ #
+ try:
+ with nogil:
+ bar(0)
+ try:
+ with nogil:
+ bar(1)
+ except ValueError:
+ with nogil:
+ bar(1)
+ finally:
+ with nogil:
+ bar(1)
+ pass
+ except ValueError:
+ with nogil:
+ bar(0)
+ finally:
+ with nogil:
+ bar(0)
+ pass
+ #
+
+def test_spam():
+ """
+ >>> test_spam()
+ """
+ #
+ spam(0)
+ spam(0)
+ with nogil:
+ spam(0)
+ spam(0)
+ #
+ try:
+ with nogil:
+ spam(0)
+ finally:
+ pass
+ #
+ try:
+ with nogil:
+ spam(0)
+ with nogil:
+ spam(0)
+ finally:
+ pass
+ #
+ try:
+ with nogil:
+ spam(0)
+ with nogil:
+ spam(1)
+ except TypeError:
+ with nogil:
+ spam(0)
+ finally:
+ with nogil:
+ spam(0)
+ pass
+ #
+ try:
+ with nogil:
+ spam(0)
+ spam(0)
+ finally:
+ pass
+ #
+ try:
+ with nogil:
+ spam(0)
+ spam(1)
+ except TypeError:
+ with nogil:
+ spam(0)
+ finally:
+ with nogil:
+ spam(0)
+ pass
+ #
+ try:
+ with nogil:
+ spam(0)
+ try:
+ with nogil:
+ spam(1)
+ except TypeError:
+ with nogil:
+ spam(1)
+ finally:
+ with nogil:
+ spam(0)
+ pass
+ except TypeError:
+ with nogil:
+ spam(0)
+ finally:
+ with nogil:
+ spam(0)
+ pass
+ #
+ try:
+ with nogil:
+ spam(0)
+ try:
+ with nogil:
+ spam(1)
+ except TypeError:
+ with nogil:
+ spam(1)
+ finally:
+ with nogil:
+ spam(1)
+ pass
+ except TypeError:
+ with nogil:
+ spam(0)
+ finally:
+ with nogil:
+ spam(0)
+ pass
+ #