Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
fixes
  • Loading branch information
Marcel Plch
Marcel Plch committed Dec 13, 2017
commit 11517cb1061e78273684d537880e6b9311b0fc14
2 changes: 1 addition & 1 deletion Include/pylifecycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ PyAPI_FUNC(void) Py_EndInterpreter(PyThreadState *);
* exit functions.
*/
#ifndef Py_LIMITED_API
PyAPI_FUNC(void) _Py_PyAtExit(PyObject *, void (*func)(PyObject *));
PyAPI_FUNC(void) _Py_PyAtExit(void (*func)(PyObject *), PyObject *);
#endif
PyAPI_FUNC(int) Py_AtExit(void (*func)(void));

Expand Down
19 changes: 19 additions & 0 deletions Lib/test/test_atexit.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import unittest
import io
import atexit
import os
from test import support
from test.support import script_helper

Expand Down Expand Up @@ -203,6 +204,24 @@ def f():
self.assertEqual(ret, 0)
self.assertEqual(atexit._ncallbacks(), n)

def test_callback_on_subinterpreter_teardown(self):
# This tests if a callback is called on
# subinterpreter teardown.
expected = b"The test has passed!"
r, w = os.pipe()

code = r"""if 1:
import os
import atexit
def callback():
os.write({:d}, b"The test has passed!")
atexit.register(callback)
""".format(w)
ret = support.run_in_subinterp(code)
os.close(w)
self.assertEqual(os.read(r, len(expected)), expected)
os.close(r)


if __name__ == "__main__":
unittest.main()
5 changes: 0 additions & 5 deletions Lib/test/test_embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,6 @@ def test_bpo20891(self):
self.assertEqual(out, '')
self.assertEqual(err, '')

def test_atexit_callbacks(self):
out, err = self.run_embedded_interpreter("atexit_callbacks")
expected_output = "The test has passed."
self.assertEqual(out.strip(), expected_output)


if __name__ == "__main__":
unittest.main()
2 changes: 1 addition & 1 deletion Modules/atexitmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ atexit_exec(PyObject *m) {
if (modstate->atexit_callbacks == NULL)
return -1;

_Py_PyAtExit(m, atexit_callfuncs);
_Py_PyAtExit(atexit_callfuncs, m);
return 0;
}

Expand Down
83 changes: 0 additions & 83 deletions Programs/_testembed.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,88 +195,6 @@ static int test_bpo20891(void)
}


static int test_atexit_callbacks(void) {
PyObject *pName = NULL, *pModule = NULL, *pFunc = NULL;
PyObject *pArgs = NULL, *pValue = NULL;
PyObject *ax_name = NULL, *ax_module = NULL;
PyThreadState *subinterpret = NULL;
PyThreadState *mainState = NULL;

_testembed_Py_Initialize();
mainState = PyThreadState_Get();
if (mainState == NULL) {
goto error;
}
subinterpret = Py_NewInterpreter();
if (subinterpret == NULL) {
goto error;
}
PyThreadState_Swap(subinterpret);
pName = PyUnicode_FromString("builtins");
if (pName == NULL) {
goto error;
}
ax_name = PyUnicode_FromString("atexit");
if (ax_name == NULL) {
goto error;
}

pModule = PyImport_Import(pName);
if (pModule == NULL) {
goto error;
}
ax_module = PyImport_Import(ax_name);
if (ax_module == NULL) {
goto error;
}
Py_CLEAR(pName);
Py_CLEAR(ax_name);

pFunc = PyObject_GetAttrString(ax_module, "register");
if (pFunc == NULL || !PyCallable_Check(pFunc)) {
goto error;
}

pArgs = PyTuple_New(4);
if (pArgs == NULL) {
goto error;
}
PyTuple_SetItem(pArgs, 0, PyObject_GetAttrString(pModule, "exec"));
PyTuple_SetItem(pArgs, 1, PyUnicode_FromString("import sys;"
"print('The test has passed.');"
"sys.stdout.flush()"));
PyTuple_SetItem(pArgs, 2, PyDict_New());
PyTuple_SetItem(pArgs, 3, PyDict_New());
pValue = PyObject_CallObject(pFunc, pArgs);
if (pValue == NULL) {
goto error;
}
Py_CLEAR(pArgs);
Py_CLEAR(pValue);
Py_CLEAR(pFunc);
Py_CLEAR(pModule);
PyErr_Clear();
Py_EndInterpreter(subinterpret);
PyThreadState_Swap(mainState);
if (Py_FinalizeEx() < 0) {
return -1;
}
return 0;

error:
Py_XDECREF(pName);
Py_XDECREF(pModule);
Py_XDECREF(pFunc);
Py_XDECREF(pArgs);
Py_XDECREF(pValue);
Py_XDECREF(ax_name);
Py_XDECREF(ax_module);
Py_XDECREF(subinterpret);
Py_XDECREF(mainState);
Py_Finalize();
return -1;
}

/* *********************************************************
* List of test cases and the function that implements it.
*
Expand All @@ -300,7 +218,6 @@ static struct TestCase TestCases[] = {
{ "repeated_init_and_subinterpreters", test_repeated_init_and_subinterpreters },
{ "pre_initialization_api", test_pre_initialization_api },
{ "bpo20891", test_bpo20891 },
{ "atexit_callbacks", test_atexit_callbacks },
{ NULL, NULL }
};

Expand Down
2 changes: 1 addition & 1 deletion Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -2098,7 +2098,7 @@ _Py_FatalInitError(_PyInitError err)
# include "pythread.h"

/* For the atexit module. */
void _Py_PyAtExit(PyObject *module, void (*func)(PyObject *))
void _Py_PyAtExit(void (*func)(PyObject *), PyObject *module)
{
PyThreadState *ts;
PyInterpreterState *is;
Expand Down