diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py index 84ec9ed150fc4e9dd8287edd9ee574b56d663a75..9c8f82fa08105c27d422d03fe2803aac936016cb 100644 --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -1028,6 +1028,8 @@ def make_wrapper_second_level(space, argtypesw, restype, except OperationError as e: failed = True state.set_exception(e) + if e.match(space, space.w_SystemExit): + raise e except BaseException as e: failed = True if not we_are_translated(): @@ -1068,6 +1070,10 @@ def make_wrapper_second_level(space, argtypesw, restype, elif restype is not lltype.Void: retval = rffi.cast(restype, result) + except OperationError as e: + _restore_gil_state(pygilstate_release, gilstate, gil_release, _gil_auto) + raise e + return fatal_value except Exception as e: unexpected_exception(pname, e, tb) _restore_gil_state(pygilstate_release, gilstate, gil_release, _gil_auto) diff --git a/pypy/module/cpyext/pythonrun.py b/pypy/module/cpyext/pythonrun.py index 19fe20af86d3739d6f1202f59955872c472a8884..317e6cf496c5b07d2c0cbb1a0c87d9b753de554f 100644 --- a/pypy/module/cpyext/pythonrun.py +++ b/pypy/module/cpyext/pythonrun.py @@ -1,4 +1,5 @@ from rpython.rtyper.lltypesystem import rffi, lltype +from pypy.interpreter.error import OperationError from pypy.module.cpyext.api import cpython_api, CANNOT_FAIL from pypy.module.cpyext.state import State @@ -46,3 +47,9 @@ def Py_AtExit(space, func_ptr): except ValueError: return -1 return 0 + +@cpython_api([rffi.INT_real], lltype.Void, error=-1) +def Py_Exit(space, status): + """Exit the current process. This calls Py_Finalize() and then calls the + standard C library function exit(status).""" + raise OperationError(space.w_SystemExit, space.newint(status)) diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py index 3dba4ffa8a9d6b100efccd1e899a52f914028ad5..431350c78e90c231f9a2433c458dccf64bb427ba 100644 --- a/pypy/module/cpyext/stubs.py +++ b/pypy/module/cpyext/stubs.py @@ -1344,12 +1344,6 @@ def PySys_SetPath(space, path): (: on Unix, ; on Windows).""" raise NotImplementedError -@cpython_api([rffi.INT_real], lltype.Void) -def Py_Exit(space, status): - """Exit the current process. This calls Py_Finalize() and then calls the - standard C library function exit(status).""" - raise NotImplementedError - @cpython_api([], rffi.INT_real, error=CANNOT_FAIL) def PyTuple_ClearFreeList(space): """Clear the free list. Return the total number of freed items. diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py index 997357716a8d1d31ef7e404b905ec92e8759da51..317d3ba5e7c56aa3dcb538af2ccb679e7c12153f 100644 --- a/pypy/module/cpyext/test/test_cpyext.py +++ b/pypy/module/cpyext/test/test_cpyext.py @@ -937,3 +937,22 @@ class AppTestCpythonExtension(AppTestCpythonExtensionBase): ''' ), ]) + + def test_call_py_exit(self): + try: + import posix + except ImportError: + skip("requires posix.fork() to test") + mod = self.import_extension('foo', [ + ('exit', 'METH_NOARGS', + ''' + Py_Exit(42); + ''')]) + # run the function in a thread + pid = posix.fork() + if pid == 0: + mod.exit() + pid, status = posix.waitpid(pid, 0) + print pid, status + assert posix.WIFEXITED(status) + assert posix.WEXITSTATUS(status) == 42