-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
bpo-42972: Fully support GC for _winapi.Overlapped #26381
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0fa0217
9f3ca36
96f0d0e
0493de0
fc3e774
78113cc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -112,6 +112,20 @@ typedef struct { | |
Py_buffer write_buffer; | ||
} OverlappedObject; | ||
|
||
/* | ||
Note: tp_clear (overlapped_clear) is not implemented because it | ||
requires cancelling the IO operation if it's pending and the cancellation is | ||
quite complex and can fail (see: overlapped_dealloc). | ||
*/ | ||
static int | ||
overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg) | ||
{ | ||
Py_VISIT(self->read_buffer); | ||
Py_VISIT(self->write_buffer.obj); | ||
Py_VISIT(Py_TYPE(self)); | ||
return 0; | ||
} | ||
|
||
static void | ||
overlapped_dealloc(OverlappedObject *self) | ||
{ | ||
|
@@ -150,6 +164,7 @@ overlapped_dealloc(OverlappedObject *self) | |
|
||
CloseHandle(self->overlapped.hEvent); | ||
SetLastError(err); | ||
PyObject_GC_UnTrack(self); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer to start by untracking the GC, at the start to the dealloc function. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I initially did that, but a concern was brought up here which I think makes sense #26381 (comment). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If tp_dealloc returns without clearing the object, IMO it's better to remove it from the GC. It's better to hide this badly broken Python object. I suggest to start by untracking and explain that it's a deliberate choice to untrack even if we hit the worst case scenario of "return" below. Note: IMO this code should be removed, Windows XP is no longer supported, but it should be done in a separated change. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I just introduced a regression with this, seems like there's a race condition with the GC and the IO operation somewhere.
It seems that placing the |
||
if (self->write_buffer.obj) | ||
PyBuffer_Release(&self->write_buffer); | ||
Py_CLEAR(self->read_buffer); | ||
|
@@ -321,6 +336,7 @@ static PyMemberDef overlapped_members[] = { | |
}; | ||
|
||
static PyType_Slot winapi_overlapped_type_slots[] = { | ||
{Py_tp_traverse, overlapped_traverse}, | ||
{Py_tp_dealloc, overlapped_dealloc}, | ||
{Py_tp_doc, "OVERLAPPED structure wrapper"}, | ||
{Py_tp_methods, overlapped_methods}, | ||
|
@@ -331,15 +347,16 @@ static PyType_Slot winapi_overlapped_type_slots[] = { | |
static PyType_Spec winapi_overlapped_type_spec = { | ||
.name = "_winapi.Overlapped", | ||
.basicsize = sizeof(OverlappedObject), | ||
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, | ||
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION | | ||
Py_TPFLAGS_HAVE_GC), | ||
.slots = winapi_overlapped_type_slots, | ||
}; | ||
|
||
static OverlappedObject * | ||
new_overlapped(PyObject *module, HANDLE handle) | ||
{ | ||
WinApiState *st = winapi_get_state(module); | ||
OverlappedObject *self = PyObject_New(OverlappedObject, st->overlapped_type); | ||
OverlappedObject *self = PyObject_GC_New(OverlappedObject, st->overlapped_type); | ||
if (!self) | ||
return NULL; | ||
|
||
|
@@ -351,6 +368,8 @@ new_overlapped(PyObject *module, HANDLE handle) | |
memset(&self->write_buffer, 0, sizeof(Py_buffer)); | ||
/* Manual reset, initially non-signalled */ | ||
self->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); | ||
|
||
PyObject_GC_Track(self); | ||
return self; | ||
} | ||
|
||
|
@@ -2043,12 +2062,37 @@ static PyModuleDef_Slot winapi_slots[] = { | |
{0, NULL} | ||
}; | ||
|
||
static int | ||
winapi_traverse(PyObject *module, visitproc visit, void *arg) | ||
{ | ||
WinApiState *st = winapi_get_state(module); | ||
Py_VISIT(st->overlapped_type); | ||
return 0; | ||
} | ||
|
||
static int | ||
winapi_clear(PyObject *module) | ||
{ | ||
WinApiState *st = winapi_get_state(module); | ||
Py_CLEAR(st->overlapped_type); | ||
return 0; | ||
} | ||
|
||
static void | ||
winapi_free(void *module) | ||
{ | ||
winapi_clear((PyObject *)module); | ||
} | ||
|
||
static struct PyModuleDef winapi_module = { | ||
PyModuleDef_HEAD_INIT, | ||
.m_name = "_winapi", | ||
.m_size = sizeof(WinApiState), | ||
.m_methods = winapi_functions, | ||
.m_slots = winapi_slots, | ||
.m_traverse = winapi_traverse, | ||
.m_clear = winapi_clear, | ||
.m_free = winapi_free, | ||
}; | ||
|
||
PyMODINIT_FUNC | ||
|
Uh oh!
There was an error while loading. Please reload this page.