Skip to content

Commit 0d39951

Browse files
[3.10] bpo-42972: Fully support GC for _winapi.Overlapped (GH-26381) (#26430)
* bpo-42972: Fully support GC for _winapi.Overlapped (GH-26381) * untrack earlier
1 parent 1c0106c commit 0d39951

File tree

1 file changed

+46
-2
lines changed

1 file changed

+46
-2
lines changed

Modules/_winapi.c

+46-2
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,27 @@ typedef struct {
112112
Py_buffer write_buffer;
113113
} OverlappedObject;
114114

115+
/*
116+
Note: tp_clear (overlapped_clear) is not implemented because it
117+
requires cancelling the IO operation if it's pending and the cancellation is
118+
quite complex and can fail (see: overlapped_dealloc).
119+
*/
120+
static int
121+
overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg)
122+
{
123+
Py_VISIT(self->read_buffer);
124+
Py_VISIT(self->write_buffer.obj);
125+
Py_VISIT(Py_TYPE(self));
126+
return 0;
127+
}
128+
115129
static void
116130
overlapped_dealloc(OverlappedObject *self)
117131
{
118132
DWORD bytes;
119133
int err = GetLastError();
120134

135+
PyObject_GC_UnTrack(self);
121136
if (self->pending) {
122137
if (check_CancelIoEx() &&
123138
Py_CancelIoEx(self->handle, &self->overlapped) &&
@@ -321,6 +336,7 @@ static PyMemberDef overlapped_members[] = {
321336
};
322337

323338
static PyType_Slot winapi_overlapped_type_slots[] = {
339+
{Py_tp_traverse, overlapped_traverse},
324340
{Py_tp_dealloc, overlapped_dealloc},
325341
{Py_tp_doc, "OVERLAPPED structure wrapper"},
326342
{Py_tp_methods, overlapped_methods},
@@ -331,15 +347,16 @@ static PyType_Slot winapi_overlapped_type_slots[] = {
331347
static PyType_Spec winapi_overlapped_type_spec = {
332348
.name = "_winapi.Overlapped",
333349
.basicsize = sizeof(OverlappedObject),
334-
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION,
350+
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
351+
Py_TPFLAGS_HAVE_GC),
335352
.slots = winapi_overlapped_type_slots,
336353
};
337354

338355
static OverlappedObject *
339356
new_overlapped(PyObject *module, HANDLE handle)
340357
{
341358
WinApiState *st = winapi_get_state(module);
342-
OverlappedObject *self = PyObject_New(OverlappedObject, st->overlapped_type);
359+
OverlappedObject *self = PyObject_GC_New(OverlappedObject, st->overlapped_type);
343360
if (!self)
344361
return NULL;
345362

@@ -351,6 +368,8 @@ new_overlapped(PyObject *module, HANDLE handle)
351368
memset(&self->write_buffer, 0, sizeof(Py_buffer));
352369
/* Manual reset, initially non-signalled */
353370
self->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
371+
372+
PyObject_GC_Track(self);
354373
return self;
355374
}
356375

@@ -2043,12 +2062,37 @@ static PyModuleDef_Slot winapi_slots[] = {
20432062
{0, NULL}
20442063
};
20452064

2065+
static int
2066+
winapi_traverse(PyObject *module, visitproc visit, void *arg)
2067+
{
2068+
WinApiState *st = winapi_get_state(module);
2069+
Py_VISIT(st->overlapped_type);
2070+
return 0;
2071+
}
2072+
2073+
static int
2074+
winapi_clear(PyObject *module)
2075+
{
2076+
WinApiState *st = winapi_get_state(module);
2077+
Py_CLEAR(st->overlapped_type);
2078+
return 0;
2079+
}
2080+
2081+
static void
2082+
winapi_free(void *module)
2083+
{
2084+
winapi_clear((PyObject *)module);
2085+
}
2086+
20462087
static struct PyModuleDef winapi_module = {
20472088
PyModuleDef_HEAD_INIT,
20482089
.m_name = "_winapi",
20492090
.m_size = sizeof(WinApiState),
20502091
.m_methods = winapi_functions,
20512092
.m_slots = winapi_slots,
2093+
.m_traverse = winapi_traverse,
2094+
.m_clear = winapi_clear,
2095+
.m_free = winapi_free,
20522096
};
20532097

20542098
PyMODINIT_FUNC

0 commit comments

Comments
 (0)