Skip to content

Commit dea173a

Browse files
Clear the XID classes during module fini.
1 parent da9779f commit dea173a

File tree

1 file changed

+93
-43
lines changed

1 file changed

+93
-43
lines changed

Modules/_xxinterpchannelsmodule.c

Lines changed: 93 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,74 @@ API.. The module does not create any objects that are shared globally.
8282
PyMem_RawFree(VAR)
8383

8484

85+
struct xid_class_registry {
86+
size_t count;
87+
#define MAX_XID_CLASSES 5
88+
struct {
89+
PyTypeObject *cls;
90+
} added[MAX_XID_CLASSES];
91+
};
92+
93+
static int
94+
register_xid_class(PyTypeObject *cls, crossinterpdatafunc shared,
95+
struct xid_class_registry *classes)
96+
{
97+
int res = _PyCrossInterpreterData_RegisterClass(cls, shared);
98+
if (res == 0) {
99+
assert(classes->count < MAX_XID_CLASSES);
100+
Py_INCREF(cls);
101+
classes->added[classes->count].cls = cls;
102+
classes->count += 1;
103+
}
104+
return res;
105+
}
106+
107+
static void
108+
clear_xid_class_registry(struct xid_class_registry *classes)
109+
{
110+
while (classes->count > 0) {
111+
classes->count -= 1;
112+
PyTypeObject *cls = classes->added[classes->count].cls;
113+
_PyCrossInterpreterData_UnregisterClass(cls);
114+
Py_DECREF(cls);
115+
}
116+
}
117+
118+
#define XID_IGNORE_EXC 1
119+
#define XID_FREE 2
120+
121+
static int
122+
_release_xid_data(_PyCrossInterpreterData *data, int flags)
123+
{
124+
int ignoreexc = flags & XID_IGNORE_EXC;
125+
PyObject *exc;
126+
if (ignoreexc) {
127+
exc = PyErr_GetRaisedException();
128+
}
129+
int res;
130+
if (flags & XID_FREE) {
131+
res = _PyCrossInterpreterData_ReleaseAndRawFree(data);
132+
}
133+
else {
134+
res = _PyCrossInterpreterData_Release(data);
135+
}
136+
if (res < 0) {
137+
/* The owning interpreter is already destroyed. */
138+
if (ignoreexc) {
139+
// XXX Emit a warning?
140+
PyErr_Clear();
141+
}
142+
}
143+
if (flags & XID_FREE) {
144+
/* Either way, we free the data. */
145+
}
146+
if (ignoreexc) {
147+
PyErr_SetRaisedException(exc);
148+
}
149+
return res;
150+
}
151+
152+
85153
static PyInterpreterState *
86154
_get_current_interp(void)
87155
{
@@ -146,7 +214,8 @@ add_new_exception(PyObject *mod, const char *name, PyObject *base)
146214
add_new_exception(MOD, MODULE_NAME "." Py_STRINGIFY(NAME), BASE)
147215

148216
static PyTypeObject *
149-
add_new_type(PyObject *mod, PyType_Spec *spec, crossinterpdatafunc shared)
217+
add_new_type(PyObject *mod, PyType_Spec *spec, crossinterpdatafunc shared,
218+
struct xid_class_registry *classes)
150219
{
151220
PyTypeObject *cls = (PyTypeObject *)PyType_FromMetaclass(
152221
NULL, mod, spec, NULL);
@@ -158,48 +227,14 @@ add_new_type(PyObject *mod, PyType_Spec *spec, crossinterpdatafunc shared)
158227
return NULL;
159228
}
160229
if (shared != NULL) {
161-
if (_PyCrossInterpreterData_RegisterClass(cls, shared)) {
230+
if (register_xid_class(cls, shared, classes)) {
162231
Py_DECREF(cls);
163232
return NULL;
164233
}
165234
}
166235
return cls;
167236
}
168237

169-
#define XID_IGNORE_EXC 1
170-
#define XID_FREE 2
171-
172-
static int
173-
_release_xid_data(_PyCrossInterpreterData *data, int flags)
174-
{
175-
int ignoreexc = flags & XID_IGNORE_EXC;
176-
PyObject *exc;
177-
if (ignoreexc) {
178-
exc = PyErr_GetRaisedException();
179-
}
180-
int res;
181-
if (flags & XID_FREE) {
182-
res = _PyCrossInterpreterData_ReleaseAndRawFree(data);
183-
}
184-
else {
185-
res = _PyCrossInterpreterData_Release(data);
186-
}
187-
if (res < 0) {
188-
/* The owning interpreter is already destroyed. */
189-
if (ignoreexc) {
190-
// XXX Emit a warning?
191-
PyErr_Clear();
192-
}
193-
}
194-
if (flags & XID_FREE) {
195-
/* Either way, we free the data. */
196-
}
197-
if (ignoreexc) {
198-
PyErr_SetRaisedException(exc);
199-
}
200-
return res;
201-
}
202-
203238

204239
/* Cross-interpreter Buffer Views *******************************************/
205240

@@ -315,15 +350,15 @@ _memoryview_shared(PyThreadState *tstate, PyObject *obj,
315350
}
316351

317352
static int
318-
register_xid_types(void)
353+
register_builtin_xid_types(struct xid_class_registry *classes)
319354
{
320355
PyTypeObject *cls;
321356
crossinterpdatafunc func;
322357

323358
// builtin memoryview
324359
cls = &PyMemoryView_Type;
325360
func = _memoryview_shared;
326-
if (_PyCrossInterpreterData_RegisterClass(cls, func)) {
361+
if (register_xid_class(cls, func, classes)) {
327362
return -1;
328363
}
329364

@@ -334,6 +369,9 @@ register_xid_types(void)
334369
/* module state *************************************************************/
335370

336371
typedef struct {
372+
struct xid_class_registry xid_classes;
373+
374+
/* Added at runtime by interpreters module. */
337375
PyTypeObject *send_channel_type;
338376
PyTypeObject *recv_channel_type;
339377

@@ -2191,6 +2229,7 @@ set_channel_end_types(PyObject *mod, PyTypeObject *send, PyTypeObject *recv)
21912229
if (state == NULL) {
21922230
return -1;
21932231
}
2232+
struct xid_class_registry *xid_classes = &state->xid_classes;
21942233

21952234
if (state->send_channel_type != NULL
21962235
|| state->recv_channel_type != NULL)
@@ -2201,10 +2240,10 @@ set_channel_end_types(PyObject *mod, PyTypeObject *send, PyTypeObject *recv)
22012240
state->send_channel_type = (PyTypeObject *)Py_NewRef(send);
22022241
state->recv_channel_type = (PyTypeObject *)Py_NewRef(recv);
22032242

2204-
if (_PyCrossInterpreterData_RegisterClass(send, _channel_end_shared)) {
2243+
if (register_xid_class(send, _channel_end_shared, xid_classes)) {
22052244
return -1;
22062245
}
2207-
if (_PyCrossInterpreterData_RegisterClass(recv, _channel_end_shared)) {
2246+
if (register_xid_class(recv, _channel_end_shared, xid_classes)) {
22082247
return -1;
22092248
}
22102249

@@ -2722,6 +2761,7 @@ module_exec(PyObject *mod)
27222761
if (_globals_init() != 0) {
27232762
return -1;
27242763
}
2764+
struct xid_class_registry *xid_classes = NULL;
27252765

27262766
/* Add exception types */
27272767
if (exceptions_init(mod) != 0) {
@@ -2733,20 +2773,22 @@ module_exec(PyObject *mod)
27332773
if (state == NULL) {
27342774
goto error;
27352775
}
2776+
xid_classes = &state->xid_classes;
27362777

27372778
// ChannelID
27382779
state->ChannelIDType = add_new_type(
2739-
mod, &ChannelIDType_spec, _channelid_shared);
2780+
mod, &ChannelIDType_spec, _channelid_shared, xid_classes);
27402781
if (state->ChannelIDType == NULL) {
27412782
goto error;
27422783
}
27432784

2744-
state->XIBufferViewType = add_new_type(mod, &XIBufferViewType_spec, NULL);
2785+
state->XIBufferViewType = add_new_type(mod, &XIBufferViewType_spec, NULL,
2786+
xid_classes);
27452787
if (state->XIBufferViewType == NULL) {
27462788
goto error;
27472789
}
27482790

2749-
if (register_xid_types() < 0) {
2791+
if (register_builtin_xid_types(xid_classes) < 0) {
27502792
goto error;
27512793
}
27522794

@@ -2757,6 +2799,9 @@ module_exec(PyObject *mod)
27572799
return 0;
27582800

27592801
error:
2802+
if (xid_classes != NULL) {
2803+
clear_xid_class_registry(xid_classes);
2804+
}
27602805
_globals_fini();
27612806
return -1;
27622807
}
@@ -2781,6 +2826,11 @@ module_clear(PyObject *mod)
27812826
{
27822827
module_state *state = get_module_state(mod);
27832828
assert(state != NULL);
2829+
2830+
// Before clearing anything, we unregister the various XID types. */
2831+
clear_xid_class_registry(&state->xid_classes);
2832+
2833+
// Now we clear the module state.
27842834
clear_module_state(state);
27852835
return 0;
27862836
}

0 commit comments

Comments
 (0)