Skip to content

bpo-1635741: - port overlapped to multi-phase #22051

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

Merged
merged 4 commits into from
Sep 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Port the :mod:`_overlapped` extension module to multi-phase initialization
(:pep:`489`).
173 changes: 106 additions & 67 deletions Modules/overlapped.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,19 @@ typedef struct {
};
} OverlappedObject;

typedef struct {
PyTypeObject *overlapped_type;
} OverlappedState;

static inline OverlappedState*
overlapped_get_state(PyObject *module)
{
void *state = PyModule_GetState(module);
assert(state != NULL);
return (OverlappedState *)state;
}


/*
* Map Windows error codes to subclasses of OSError
*/
Expand Down Expand Up @@ -706,8 +719,11 @@ Overlapped_dealloc(OverlappedObject *self)
}

Overlapped_clear(self);
PyObject_Del(self);
SetLastError(olderr);

PyTypeObject *tp = Py_TYPE(self);
PyObject_Del(self);
Py_DECREF(tp);
}


Expand Down Expand Up @@ -1846,45 +1862,22 @@ static PyGetSetDef Overlapped_getsets[] = {
{NULL},
};

PyTypeObject OverlappedType = {
PyVarObject_HEAD_INIT(NULL, 0)
/* tp_name */ "_overlapped.Overlapped",
/* tp_basicsize */ sizeof(OverlappedObject),
/* tp_itemsize */ 0,
/* tp_dealloc */ (destructor) Overlapped_dealloc,
/* tp_vectorcall_offset */ 0,
/* tp_getattr */ 0,
/* tp_setattr */ 0,
/* tp_as_async */ 0,
/* tp_repr */ 0,
/* tp_as_number */ 0,
/* tp_as_sequence */ 0,
/* tp_as_mapping */ 0,
/* tp_hash */ 0,
/* tp_call */ 0,
/* tp_str */ 0,
/* tp_getattro */ 0,
/* tp_setattro */ 0,
/* tp_as_buffer */ 0,
/* tp_flags */ Py_TPFLAGS_DEFAULT,
/* tp_doc */ _overlapped_Overlapped__doc__,
/* tp_traverse */ (traverseproc)Overlapped_traverse,
/* tp_clear */ 0,
/* tp_richcompare */ 0,
/* tp_weaklistoffset */ 0,
/* tp_iter */ 0,
/* tp_iternext */ 0,
/* tp_methods */ Overlapped_methods,
/* tp_members */ Overlapped_members,
/* tp_getset */ Overlapped_getsets,
/* tp_base */ 0,
/* tp_dict */ 0,
/* tp_descr_get */ 0,
/* tp_descr_set */ 0,
/* tp_dictoffset */ 0,
/* tp_init */ 0,
/* tp_alloc */ 0,
/* tp_new */ _overlapped_Overlapped,
static PyType_Slot overlapped_type_slots[] = {
{Py_tp_dealloc, Overlapped_dealloc},
{Py_tp_doc, (char *)_overlapped_Overlapped__doc__},
{Py_tp_traverse, Overlapped_traverse},
{Py_tp_methods, Overlapped_methods},
{Py_tp_members, Overlapped_members},
{Py_tp_getset, Overlapped_getsets},
{Py_tp_new, _overlapped_Overlapped},
{0,0}
};

static PyType_Spec overlapped_type_spec = {
.name = "_overlapped.Overlapped",
.basicsize = sizeof(OverlappedObject),
.flags = Py_TPFLAGS_DEFAULT,
.slots = overlapped_type_slots
};

static PyMethodDef overlapped_functions[] = {
Expand All @@ -1904,41 +1897,65 @@ static PyMethodDef overlapped_functions[] = {
{NULL}
};

static struct PyModuleDef overlapped_module = {
PyModuleDef_HEAD_INIT,
"_overlapped",
NULL,
-1,
overlapped_functions,
NULL,
NULL,
NULL,
NULL
};
static int
overlapped_traverse(PyObject *module, visitproc visit, void *arg)
{
OverlappedState *state = overlapped_get_state(module);
Py_VISIT(state->overlapped_type);
return 0;
}

#define WINAPI_CONSTANT(fmt, con) \
PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con))
static int
overlapped_clear(PyObject *module)
{
OverlappedState *state = overlapped_get_state(module);
Py_CLEAR(state->overlapped_type);
return 0;
}

PyMODINIT_FUNC
PyInit__overlapped(void)
static void
overlapped_free(void *module)
{
PyObject *m, *d;
overlapped_clear((PyObject *)module);
}

#define WINAPI_CONSTANT(fmt, con) \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this can be converted into PyModule_AddObject instead of using PyModule_GetDict

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@corona10 You're right. Is that preferable to PyModule_GetDict? If so why?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://docs.python.org/3/c-api/module.html?highlight=pymodule_getdict#c.PyModule_GetDict

It is recommended extensions use other PyModule_*() and PyObject_*() functions rather than directly manipulate a module’s __dict__.

Copy link
Contributor Author

@koubaa koubaa Sep 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@corona10 I'm trying that now. So far it is not looking good - somehow the values are all wrong. For example when I switch to PyModule_AddObject, overlapped.__dict__["ERROR_IO_PENDING"] is 6160 instead of 997. I can't figure out why..

Edit - I figured it out. I was doing a decref on the object I passed into PyModule_AddObject, but it turns out this function steals the reference so I shouldn't do that.

do { \
PyObject *value = Py_BuildValue(fmt, con); \
if (value == NULL) { \
return -1; \
} \
if (PyModule_AddObject(module, #con, value) < 0 ) { \
Py_DECREF(value); \
return -1; \
} \
} while (0)

static int
overlapped_exec(PyObject *module)
{
/* Ensure WSAStartup() called before initializing function pointers */
m = PyImport_ImportModule("_socket");
if (!m)
return NULL;
Py_DECREF(m);
PyObject *socket_module = PyImport_ImportModule("_socket");
if (!socket_module) {
return -1;
}

if (initialize_function_pointers() < 0)
return NULL;
Py_DECREF(socket_module);

m = PyModule_Create(&overlapped_module);
if (PyModule_AddType(m, &OverlappedType) < 0) {
return NULL;
if (initialize_function_pointers() < 0) {
return -1;
}

d = PyModule_GetDict(m);
OverlappedState *st = overlapped_get_state(module);
st->overlapped_type = (PyTypeObject *)PyType_FromModuleAndSpec(
module, &overlapped_type_spec, NULL);
if (st->overlapped_type == NULL) {
return -1;
}

if (PyModule_AddType(module, st->overlapped_type) < 0) {
return -1;
}

WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
Expand All @@ -1952,5 +1969,27 @@ PyInit__overlapped(void)
WINAPI_CONSTANT(F_DWORD, SO_UPDATE_CONNECT_CONTEXT);
WINAPI_CONSTANT(F_DWORD, TF_REUSE_SOCKET);

return m;
return 0;
}

static PyModuleDef_Slot overlapped_slots[] = {
{Py_mod_exec, overlapped_exec},
{0, NULL}
};

static struct PyModuleDef overlapped_module = {
PyModuleDef_HEAD_INIT,
.m_name = "_overlapped",
.m_size = sizeof(OverlappedState),
.m_methods = overlapped_functions,
.m_slots = overlapped_slots,
.m_traverse = overlapped_traverse,
.m_clear = overlapped_clear,
.m_free = overlapped_free
};

PyMODINIT_FUNC
PyInit__overlapped(void)
{
return PyModuleDef_Init(&overlapped_module);
}