Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9c94ba4

Browse files
committed
Issue python#4200: Changed the atexit module to store its state in its PyModuleDef atexitmodule. This fixes a bug with multiple subinterpeters. The bug was found by Graham Dumpletom during his work on a 3.0 port of mod_wsgi. The patch has been reviewed by Benjamin.
1 parent df32b39 commit 9c94ba4

2 files changed

Lines changed: 85 additions & 50 deletions

File tree

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ What's New in Python 3.0 beta 5
1515
Core and Builtins
1616
-----------------
1717

18+
- Issue #4200: Changed the atexit module to store its state in its
19+
PyModuleDef atexitmodule. This fixes a bug with multiple subinterpeters.
20+
1821
- Issue #4237: io.FileIO() was raising invalid warnings caused by
1922
insufficient initialization of PyFileIOObject struct members.
2023

Modules/atexitmodule.c

Lines changed: 82 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
#include "Python.h"
1010

1111
/* Forward declaration (for atexit_cleanup) */
12-
static PyObject *atexit_clear(PyObject*);
12+
static PyObject *atexit_clear(PyObject*, PyObject*);
1313
/* Forward declaration (for atexit_callfuncs) */
14-
static void atexit_cleanup(void);
14+
static void atexit_cleanup(PyObject*);
15+
/* Forward declaration of module object */
16+
static struct PyModuleDef atexitmodule;
1517

1618
/* ===================================================================== */
1719
/* Callback machinery. */
@@ -22,9 +24,14 @@ typedef struct {
2224
PyObject *kwargs;
2325
} atexit_callback;
2426

25-
static atexit_callback **atexit_callbacks;
26-
static int ncallbacks = 0;
27-
static int callback_len = 32;
27+
typedef struct {
28+
atexit_callback **atexit_callbacks;
29+
int ncallbacks;
30+
int callback_len;
31+
} atexitmodule_state;
32+
33+
#define GET_ATEXIT_STATE(mod) ((atexitmodule_state*)PyModule_GetState(mod))
34+
2835

2936
/* Installed into pythonrun.c's atexit mechanism */
3037

@@ -33,14 +40,22 @@ atexit_callfuncs(void)
3340
{
3441
PyObject *exc_type = NULL, *exc_value, *exc_tb, *r;
3542
atexit_callback *cb;
43+
PyObject *module;
44+
atexitmodule_state *modstate;
3645
int i;
37-
38-
if (ncallbacks == 0)
46+
47+
module = PyState_FindModule(&atexitmodule);
48+
if (module == NULL)
3949
return;
40-
41-
for (i = ncallbacks - 1; i >= 0; i--)
50+
modstate = GET_ATEXIT_STATE(module);
51+
52+
if (modstate->ncallbacks == 0)
53+
return;
54+
55+
56+
for (i = modstate->ncallbacks - 1; i >= 0; i--)
4257
{
43-
cb = atexit_callbacks[i];
58+
cb = modstate->atexit_callbacks[i];
4459
if (cb == NULL)
4560
continue;
4661

@@ -61,28 +76,32 @@ atexit_callfuncs(void)
6176
}
6277
}
6378
}
64-
65-
atexit_cleanup();
79+
80+
atexit_cleanup(module);
6681

6782
if (exc_type)
6883
PyErr_Restore(exc_type, exc_value, exc_tb);
6984
}
7085

7186
static void
72-
atexit_delete_cb(int i)
87+
atexit_delete_cb(PyObject *self, int i)
7388
{
74-
atexit_callback *cb = atexit_callbacks[i];
75-
atexit_callbacks[i] = NULL;
89+
atexitmodule_state *modstate;
90+
atexit_callback *cb;
91+
92+
modstate = GET_ATEXIT_STATE(self);
93+
cb = modstate->atexit_callbacks[i];
94+
modstate->atexit_callbacks[i] = NULL;
7695
Py_DECREF(cb->func);
7796
Py_DECREF(cb->args);
7897
Py_XDECREF(cb->kwargs);
79-
PyMem_Free(cb);
98+
PyMem_Free(cb);
8099
}
81100

82101
static void
83-
atexit_cleanup(void)
102+
atexit_cleanup(PyObject *self)
84103
{
85-
PyObject *r = atexit_clear(NULL);
104+
PyObject *r = atexit_clear(self, NULL);
86105
Py_DECREF(r);
87106
}
88107

@@ -103,32 +122,35 @@ Register a function to be executed upon normal program termination\n\
103122
static PyObject *
104123
atexit_register(PyObject *self, PyObject *args, PyObject *kwargs)
105124
{
125+
atexitmodule_state *modstate;
106126
atexit_callback *new_callback;
107127
PyObject *func = NULL;
108-
109-
if (ncallbacks >= callback_len) {
128+
129+
modstate = GET_ATEXIT_STATE(self);
130+
131+
if (modstate->ncallbacks >= modstate->callback_len) {
110132
atexit_callback **r;
111-
callback_len += 16;
112-
r = (atexit_callback**)PyMem_Realloc(atexit_callbacks,
113-
sizeof(atexit_callback*) * callback_len);
133+
modstate->callback_len += 16;
134+
r = (atexit_callback**)PyMem_Realloc(modstate->atexit_callbacks,
135+
sizeof(atexit_callback*) * modstate->callback_len);
114136
if (r == NULL)
115137
return PyErr_NoMemory();
116-
atexit_callbacks = r;
138+
modstate->atexit_callbacks = r;
117139
}
118-
140+
119141
if (PyTuple_GET_SIZE(args) == 0) {
120142
PyErr_SetString(PyExc_TypeError,
121143
"register() takes at least 1 argument (0 given)");
122144
return NULL;
123145
}
124-
146+
125147
func = PyTuple_GET_ITEM(args, 0);
126148
if (!PyCallable_Check(func)) {
127149
PyErr_SetString(PyExc_TypeError,
128150
"the first argument must be callable");
129151
return NULL;
130152
}
131-
153+
132154
new_callback = PyMem_Malloc(sizeof(atexit_callback));
133155
if (new_callback == NULL)
134156
return PyErr_NoMemory();
@@ -142,9 +164,9 @@ atexit_register(PyObject *self, PyObject *args, PyObject *kwargs)
142164
new_callback->kwargs = kwargs;
143165
Py_INCREF(func);
144166
Py_XINCREF(kwargs);
145-
146-
atexit_callbacks[ncallbacks++] = new_callback;
147-
167+
168+
modstate->atexit_callbacks[modstate->ncallbacks++] = new_callback;
169+
148170
Py_INCREF(func);
149171
return func;
150172
}
@@ -155,7 +177,7 @@ PyDoc_STRVAR(atexit_run_exitfuncs__doc__,
155177
Run all registered exit functions.");
156178

157179
static PyObject *
158-
atexit_run_exitfuncs(PyObject *self)
180+
atexit_run_exitfuncs(PyObject *self, PyObject *unused)
159181
{
160182
atexit_callfuncs();
161183
if (PyErr_Occurred())
@@ -169,20 +191,22 @@ PyDoc_STRVAR(atexit_clear__doc__,
169191
Clear the list of previously registered exit functions.");
170192

171193
static PyObject *
172-
atexit_clear(PyObject *self)
194+
atexit_clear(PyObject *self, PyObject *unused)
173195
{
196+
atexitmodule_state *modstate;
174197
atexit_callback *cb;
175198
int i;
176-
177-
for (i = 0; i < ncallbacks; i++)
178-
{
179-
cb = atexit_callbacks[i];
199+
200+
modstate = GET_ATEXIT_STATE(self);
201+
202+
for (i = 0; i < modstate->ncallbacks; i++) {
203+
cb = modstate->atexit_callbacks[i];
180204
if (cb == NULL)
181205
continue;
182-
183-
atexit_delete_cb(i);
206+
207+
atexit_delete_cb(self, i);
184208
}
185-
ncallbacks = 0;
209+
modstate->ncallbacks = 0;
186210
Py_RETURN_NONE;
187211
}
188212

@@ -197,20 +221,23 @@ atexit.register\n\
197221
static PyObject *
198222
atexit_unregister(PyObject *self, PyObject *func)
199223
{
224+
atexitmodule_state *modstate;
200225
atexit_callback *cb;
201226
int i, eq;
202-
203-
for (i = 0; i < ncallbacks; i++)
227+
228+
modstate = GET_ATEXIT_STATE(self);
229+
230+
for (i = 0; i < modstate->ncallbacks; i++)
204231
{
205-
cb = atexit_callbacks[i];
232+
cb = modstate->atexit_callbacks[i];
206233
if (cb == NULL)
207234
continue;
208-
235+
209236
eq = PyObject_RichCompareBool(cb->func, func, Py_EQ);
210237
if (eq < 0)
211238
return NULL;
212239
if (eq)
213-
atexit_delete_cb(i);
240+
atexit_delete_cb(self, i);
214241
}
215242
Py_RETURN_NONE;
216243
}
@@ -242,7 +269,7 @@ static struct PyModuleDef atexitmodule = {
242269
PyModuleDef_HEAD_INIT,
243270
"atexit",
244271
atexit__doc__,
245-
-1,
272+
sizeof(atexitmodule_state),
246273
atexit_methods,
247274
NULL,
248275
NULL,
@@ -254,15 +281,20 @@ PyMODINIT_FUNC
254281
PyInit_atexit(void)
255282
{
256283
PyObject *m;
257-
258-
atexit_callbacks = PyMem_New(atexit_callback*, callback_len);
259-
if (atexit_callbacks == NULL)
260-
return NULL;
284+
atexitmodule_state *modstate;
261285

262286
m = PyModule_Create(&atexitmodule);
263287
if (m == NULL)
264288
return NULL;
265-
289+
290+
modstate = GET_ATEXIT_STATE(m);
291+
modstate->callback_len = 32;
292+
modstate->ncallbacks = 0;
293+
modstate->atexit_callbacks = PyMem_New(atexit_callback*,
294+
modstate->callback_len);
295+
if (modstate->atexit_callbacks == NULL)
296+
return NULL;
297+
266298
_Py_PyAtExit(atexit_callfuncs);
267299
return m;
268300
}

0 commit comments

Comments
 (0)