From 2a8c7772d0dbb0d7f0ccd2e4c9c09b326d6d50e4 Mon Sep 17 00:00:00 2001 From: Lisandro Dalcin Date: Mon, 27 Sep 2010 12:58:49 -0300 Subject: [PATCH] Fix C++ exception handling for nogil functions (with Stephane Drouard) --- Cython/Compiler/ExprNodes.py | 3 + tests/run/cpp_exceptions_nogil.pyx | 307 ++++++++++++++++++++++++ tests/run/cpp_exceptions_nogil_helper.h | 6 + 3 files changed, 316 insertions(+) create mode 100644 tests/run/cpp_exceptions_nogil.pyx create mode 100644 tests/run/cpp_exceptions_nogil_helper.h diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 8946ec0c..a21254a8 100755 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -2863,6 +2863,7 @@ class SimpleCallNode(CallNode): or func_type.exception_check: self.is_temp = 1 # C++ exception handler + self.nogil = env.nogil if func_type.exception_check == '+': if func_type.exception_value is None: env.use_utility_code(cpp_exception_utility_code) @@ -2957,6 +2958,8 @@ class SimpleCallNode(CallNode): func_type.exception_value.entry.cname) else: raise_py_exception = '%s(); if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError , "Error converting c++ exception.")' % func_type.exception_value.entry.cname + if self.nogil: + raise_py_exception = 'Py_BLOCK_THREADS; %s; Py_UNBLOCK_THREADS' % raise_py_exception code.putln( "try {%s%s;} catch(...) {%s; %s}" % ( lhs, diff --git a/tests/run/cpp_exceptions_nogil.pyx b/tests/run/cpp_exceptions_nogil.pyx new file mode 100644 index 00000000..3fe98222 --- /dev/null +++ b/tests/run/cpp_exceptions_nogil.pyx @@ -0,0 +1,307 @@ +cdef int raise_TypeError() except *: + raise TypeError("custom") + +cdef extern from "cpp_exceptions_nogil_helper.h" nogil: + cdef void foo "foo"(int i) except + + cdef void bar "foo"(int i) except +ValueError + cdef void spam"foo"(int i) except +raise_TypeError + +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 + # diff --git a/tests/run/cpp_exceptions_nogil_helper.h b/tests/run/cpp_exceptions_nogil_helper.h new file mode 100644 index 00000000..63f159f1 --- /dev/null +++ b/tests/run/cpp_exceptions_nogil_helper.h @@ -0,0 +1,6 @@ +void foo(int i) { + if (i==0) + return; + else + throw i; +} -- 2.26.2