Skip to content

Commit ab17d15

Browse files
committed
Merge branch 'master' into speedup_type_creation
2 parents 1702e22 + 1f1a34c commit ab17d15

File tree

15 files changed

+460
-271
lines changed

15 files changed

+460
-271
lines changed

Doc/library/atexit.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ at interpreter termination time they will be run in the order ``C``, ``B``,
2020
program is killed by a signal not handled by Python, when a Python fatal
2121
internal error is detected, or when :func:`os._exit` is called.
2222

23+
.. versionchanged:: 3.7
24+
When used with C-API subinterpreters, registered functions
25+
are local to the interpreter they were registered in.
2326

2427
.. function:: register(func, *args, **kwargs)
2528

Doc/reference/lexical_analysis.rst

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -654,10 +654,11 @@ expression or conversion result. An empty string is passed when the
654654
format specifier is omitted. The formatted result is then included in
655655
the final value of the whole string.
656656

657-
Top-level format specifiers may include nested replacement fields.
658-
These nested fields may include their own conversion fields and
659-
:ref:`format specifiers <formatspec>`, but may not include more
660-
deeply-nested replacement fields.
657+
Top-level format specifiers may include nested replacement fields. These nested
658+
fields may include their own conversion fields and :ref:`format specifiers
659+
<formatspec>`, but may not include more deeply-nested replacement fields. The
660+
:ref:`format specifier mini-language <formatspec>` is the same as that used by
661+
the string .format() method.
661662

662663
Formatted string literals may be concatenated, but replacement fields
663664
cannot be split across literals.

Include/internal/pystate.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ typedef struct pyruntimestate {
9090
#define NEXITFUNCS 32
9191
void (*exitfuncs[NEXITFUNCS])(void);
9292
int nexitfuncs;
93-
void (*pyexitfunc)(void);
9493

9594
struct _gc_runtime_state gc;
9695
struct _warnings_runtime_state warnings;

Include/pylifecycle.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ PyAPI_FUNC(int) _PyCoreConfig_Copy(
6161
_PyCoreConfig *config,
6262
const _PyCoreConfig *config2);
6363

64-
PyAPI_FUNC(_PyInitError) _PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *, _PyCoreConfig *);
64+
PyAPI_FUNC(_PyInitError) _PyMainInterpreterConfig_Read(
65+
_PyMainInterpreterConfig *config,
66+
const _PyCoreConfig *core_config);
6567
PyAPI_FUNC(void) _PyMainInterpreterConfig_Clear(_PyMainInterpreterConfig *);
6668
PyAPI_FUNC(int) _PyMainInterpreterConfig_Copy(
6769
_PyMainInterpreterConfig *config,
@@ -90,7 +92,7 @@ PyAPI_FUNC(void) Py_EndInterpreter(PyThreadState *);
9092
* exit functions.
9193
*/
9294
#ifndef Py_LIMITED_API
93-
PyAPI_FUNC(void) _Py_PyAtExit(void (*func)(void));
95+
PyAPI_FUNC(void) _Py_PyAtExit(void (*func)(PyObject *), PyObject *);
9496
#endif
9597
PyAPI_FUNC(int) Py_AtExit(void (*func)(void));
9698

Include/pystate.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,18 @@ typedef struct {
4747
wchar_t *home; /* PYTHONHOME environment variable,
4848
see also Py_SetPythonHome(). */
4949
wchar_t *program_name; /* Program name, see also Py_GetProgramName() */
50+
51+
int argc; /* Number of command line arguments,
52+
-1 means unset */
53+
wchar_t **argv; /* sys.argv, ignored if argc is negative */
5054
} _PyCoreConfig;
5155

5256
#define _PyCoreConfig_INIT \
53-
(_PyCoreConfig){.use_hash_seed = -1, .coerce_c_locale = -1, .utf8_mode = -1}
57+
(_PyCoreConfig){ \
58+
.use_hash_seed = -1, \
59+
.coerce_c_locale = -1, \
60+
.utf8_mode = -1, \
61+
.argc = -1}
5462
/* Note: _PyCoreConfig_INIT sets other fields to 0/NULL */
5563

5664
/* Placeholders while working on the new configuration API
@@ -123,6 +131,9 @@ typedef struct _is {
123131
PyObject *after_forkers_parent;
124132
PyObject *after_forkers_child;
125133
#endif
134+
/* AtExit module */
135+
void (*pyexitfunc)(PyObject *);
136+
PyObject *pyexitmodule;
126137
} PyInterpreterState;
127138
#endif /* !Py_LIMITED_API */
128139

Lib/test/test_atexit.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import unittest
33
import io
44
import atexit
5+
import os
56
from test import support
67
from test.support import script_helper
78

@@ -203,6 +204,24 @@ def f():
203204
self.assertEqual(ret, 0)
204205
self.assertEqual(atexit._ncallbacks(), n)
205206

207+
def test_callback_on_subinterpreter_teardown(self):
208+
# This tests if a callback is called on
209+
# subinterpreter teardown.
210+
expected = b"The test has passed!"
211+
r, w = os.pipe()
212+
213+
code = r"""if 1:
214+
import os
215+
import atexit
216+
def callback():
217+
os.write({:d}, b"The test has passed!")
218+
atexit.register(callback)
219+
""".format(w)
220+
ret = support.run_in_subinterp(code)
221+
os.close(w)
222+
self.assertEqual(os.read(r, len(expected)), expected)
223+
os.close(r)
224+
206225

207226
if __name__ == "__main__":
208227
unittest.main()

Lib/test/test_descr.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,6 +1783,12 @@ class C(A):
17831783
def f(self): return "C"
17841784
class D(B, C):
17851785
pass
1786+
self.assertEqual(A.mro(), [A, object])
1787+
self.assertEqual(A.__mro__, (A, object))
1788+
self.assertEqual(B.mro(), [B, A, object])
1789+
self.assertEqual(B.__mro__, (B, A, object))
1790+
self.assertEqual(C.mro(), [C, A, object])
1791+
self.assertEqual(C.__mro__, (C, A, object))
17861792
self.assertEqual(D.mro(), [D, B, C, A, object])
17871793
self.assertEqual(D.__mro__, (D, B, C, A, object))
17881794
self.assertEqual(D().f(), "C")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The `atexit` module now has its callback stored per interpreter.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Make MRO computation faster when a class inherits from a single base.

Modules/atexitmodule.c

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,13 @@ atexit_cleanup(atexitmodule_state *modstate)
6363
/* Installed into pylifecycle.c's atexit mechanism */
6464

6565
static void
66-
atexit_callfuncs(void)
66+
atexit_callfuncs(PyObject *module)
6767
{
6868
PyObject *exc_type = NULL, *exc_value, *exc_tb, *r;
6969
atexit_callback *cb;
70-
PyObject *module;
7170
atexitmodule_state *modstate;
7271
int i;
7372

74-
module = PyState_FindModule(&atexitmodule);
7573
if (module == NULL)
7674
return;
7775
modstate = GET_ATEXIT_STATE(module);
@@ -185,7 +183,7 @@ Run all registered exit functions.");
185183
static PyObject *
186184
atexit_run_exitfuncs(PyObject *self, PyObject *unused)
187185
{
188-
atexit_callfuncs();
186+
atexit_callfuncs(self);
189187
if (PyErr_Occurred())
190188
return NULL;
191189
Py_RETURN_NONE;
@@ -225,13 +223,15 @@ atexit_m_traverse(PyObject *self, visitproc visit, void *arg)
225223
atexitmodule_state *modstate;
226224

227225
modstate = GET_ATEXIT_STATE(self);
228-
for (i = 0; i < modstate->ncallbacks; i++) {
229-
atexit_callback *cb = modstate->atexit_callbacks[i];
230-
if (cb == NULL)
231-
continue;
232-
Py_VISIT(cb->func);
233-
Py_VISIT(cb->args);
234-
Py_VISIT(cb->kwargs);
226+
if (modstate != NULL) {
227+
for (i = 0; i < modstate->ncallbacks; i++) {
228+
atexit_callback *cb = modstate->atexit_callbacks[i];
229+
if (cb == NULL)
230+
continue;
231+
Py_VISIT(cb->func);
232+
Py_VISIT(cb->args);
233+
Py_VISIT(cb->kwargs);
234+
}
235235
}
236236
return 0;
237237
}
@@ -241,7 +241,9 @@ atexit_m_clear(PyObject *self)
241241
{
242242
atexitmodule_state *modstate;
243243
modstate = GET_ATEXIT_STATE(self);
244-
atexit_cleanup(modstate);
244+
if (modstate != NULL) {
245+
atexit_cleanup(modstate);
246+
}
245247
return 0;
246248
}
247249

@@ -250,8 +252,10 @@ atexit_free(PyObject *m)
250252
{
251253
atexitmodule_state *modstate;
252254
modstate = GET_ATEXIT_STATE(m);
253-
atexit_cleanup(modstate);
254-
PyMem_Free(modstate->atexit_callbacks);
255+
if (modstate != NULL) {
256+
atexit_cleanup(modstate);
257+
PyMem_Free(modstate->atexit_callbacks);
258+
}
255259
}
256260

257261
PyDoc_STRVAR(atexit_unregister__doc__,
@@ -310,14 +314,34 @@ upon normal program termination.\n\
310314
Two public functions, register and unregister, are defined.\n\
311315
");
312316

317+
static int
318+
atexit_exec(PyObject *m) {
319+
atexitmodule_state *modstate;
320+
321+
modstate = GET_ATEXIT_STATE(m);
322+
modstate->callback_len = 32;
323+
modstate->ncallbacks = 0;
324+
modstate->atexit_callbacks = PyMem_New(atexit_callback*,
325+
modstate->callback_len);
326+
if (modstate->atexit_callbacks == NULL)
327+
return -1;
328+
329+
_Py_PyAtExit(atexit_callfuncs, m);
330+
return 0;
331+
}
332+
333+
static PyModuleDef_Slot atexit_slots[] = {
334+
{Py_mod_exec, atexit_exec},
335+
{0, NULL}
336+
};
313337

314338
static struct PyModuleDef atexitmodule = {
315339
PyModuleDef_HEAD_INIT,
316340
"atexit",
317341
atexit__doc__,
318342
sizeof(atexitmodule_state),
319343
atexit_methods,
320-
NULL,
344+
atexit_slots,
321345
atexit_m_traverse,
322346
atexit_m_clear,
323347
(freefunc)atexit_free
@@ -326,21 +350,5 @@ static struct PyModuleDef atexitmodule = {
326350
PyMODINIT_FUNC
327351
PyInit_atexit(void)
328352
{
329-
PyObject *m;
330-
atexitmodule_state *modstate;
331-
332-
m = PyModule_Create(&atexitmodule);
333-
if (m == NULL)
334-
return NULL;
335-
336-
modstate = GET_ATEXIT_STATE(m);
337-
modstate->callback_len = 32;
338-
modstate->ncallbacks = 0;
339-
modstate->atexit_callbacks = PyMem_New(atexit_callback*,
340-
modstate->callback_len);
341-
if (modstate->atexit_callbacks == NULL)
342-
return NULL;
343-
344-
_Py_PyAtExit(atexit_callfuncs);
345-
return m;
353+
return PyModuleDef_Init(&atexitmodule);
346354
}

0 commit comments

Comments
 (0)