bpo-40077: Convert _queuemodule to use heap types (GH-23136)

@vstinner / @corona10, would you mind reviewing this?
This commit is contained in:
Erlend Egeberg Aasland 2020-11-07 20:18:37 +01:00 committed by GitHub
parent 8805a4dad2
commit 01c6aa43dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 138 additions and 105 deletions

View File

@ -0,0 +1 @@
Convert :mod:`queue` to use heap types.

View File

@ -1,16 +1,22 @@
#include "Python.h" #include "Python.h"
#include "structmember.h" // PyMemberDef
#include <stddef.h> // offsetof() #include <stddef.h> // offsetof()
/*[clinic input] typedef struct {
module _queue PyTypeObject *SimpleQueueType;
class _queue.SimpleQueue "simplequeueobject *" "&PySimpleQueueType" PyObject *EmptyError;
[clinic start generated code]*/ } simplequeue_state;
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=cf49af81bcbbbea6]*/
static PyTypeObject PySimpleQueueType; /* forward decl */
static PyObject *EmptyError;
static simplequeue_state *
simplequeue_get_state(PyObject *module)
{
simplequeue_state *state = PyModule_GetState(module);
assert(state);
return state;
}
static struct PyModuleDef queuemodule;
#define simplequeue_get_state_by_type(tp) \
(simplequeue_get_state(_PyType_GetModuleByDef(type, &queuemodule)))
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
@ -21,10 +27,17 @@ typedef struct {
PyObject *weakreflist; PyObject *weakreflist;
} simplequeueobject; } simplequeueobject;
/*[clinic input]
module _queue
class _queue.SimpleQueue "simplequeueobject *" "simplequeue_get_state_by_type(type)->SimpleQueueType"
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=0a4023fe4d198c8d]*/
static void static void
simplequeue_dealloc(simplequeueobject *self) simplequeue_dealloc(simplequeueobject *self)
{ {
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self); PyObject_GC_UnTrack(self);
if (self->lock != NULL) { if (self->lock != NULL) {
/* Unlock the lock so it's safe to free it */ /* Unlock the lock so it's safe to free it */
@ -36,6 +49,7 @@ simplequeue_dealloc(simplequeueobject *self)
if (self->weakreflist != NULL) if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) self); PyObject_ClearWeakRefs((PyObject *) self);
Py_TYPE(self)->tp_free(self); Py_TYPE(self)->tp_free(self);
Py_DECREF(tp);
} }
static int static int
@ -155,6 +169,9 @@ simplequeue_pop_item(simplequeueobject *self)
/*[clinic input] /*[clinic input]
_queue.SimpleQueue.get _queue.SimpleQueue.get
cls: defining_class
/
block: bool = True block: bool = True
timeout: object = None timeout: object = None
@ -171,9 +188,9 @@ in that case).
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_queue_SimpleQueue_get_impl(simplequeueobject *self, int block, _queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
PyObject *timeout) int block, PyObject *timeout)
/*[clinic end generated code: output=ec82a7157dcccd1a input=4bf691f9f01fa297]*/ /*[clinic end generated code: output=1969aefa7db63666 input=5fc4d56b9a54757e]*/
{ {
_PyTime_t endtime = 0; _PyTime_t endtime = 0;
_PyTime_t timeout_val; _PyTime_t timeout_val;
@ -225,8 +242,10 @@ _queue_SimpleQueue_get_impl(simplequeueobject *self, int block,
return NULL; return NULL;
} }
if (r == PY_LOCK_FAILURE) { if (r == PY_LOCK_FAILURE) {
PyObject *module = PyType_GetModule(cls);
simplequeue_state *state = simplequeue_get_state(module);
/* Timed out */ /* Timed out */
PyErr_SetNone(EmptyError); PyErr_SetNone(state->EmptyError);
return NULL; return NULL;
} }
self->locked = 1; self->locked = 1;
@ -251,6 +270,9 @@ _queue_SimpleQueue_get_impl(simplequeueobject *self, int block,
/*[clinic input] /*[clinic input]
_queue.SimpleQueue.get_nowait _queue.SimpleQueue.get_nowait
cls: defining_class
/
Remove and return an item from the queue without blocking. Remove and return an item from the queue without blocking.
Only get an item if one is immediately available. Otherwise Only get an item if one is immediately available. Otherwise
@ -258,10 +280,11 @@ raise the Empty exception.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_queue_SimpleQueue_get_nowait_impl(simplequeueobject *self) _queue_SimpleQueue_get_nowait_impl(simplequeueobject *self,
/*[clinic end generated code: output=a89731a75dbe4937 input=6fe5102db540a1b9]*/ PyTypeObject *cls)
/*[clinic end generated code: output=620c58e2750f8b8a input=842f732bf04216d3]*/
{ {
return _queue_SimpleQueue_get_impl(self, 0, Py_None); return _queue_SimpleQueue_get_impl(self, cls, 0, Py_None);
} }
/*[clinic input] /*[clinic input]
@ -290,6 +313,29 @@ _queue_SimpleQueue_qsize_impl(simplequeueobject *self)
return PyList_GET_SIZE(self->lst) - self->lst_pos; return PyList_GET_SIZE(self->lst) - self->lst_pos;
} }
static int
queue_traverse(PyObject *m, visitproc visit, void *arg)
{
simplequeue_state *state = simplequeue_get_state(m);
Py_VISIT(state->SimpleQueueType);
Py_VISIT(state->EmptyError);
return 0;
}
static int
queue_clear(PyObject *m)
{
simplequeue_state *state = simplequeue_get_state(m);
Py_CLEAR(state->SimpleQueueType);
Py_CLEAR(state->EmptyError);
return 0;
}
static void
queue_free(void *m)
{
queue_clear((PyObject *)m);
}
#include "clinic/_queuemodule.c.h" #include "clinic/_queuemodule.c.h"
@ -306,48 +352,26 @@ static PyMethodDef simplequeue_methods[] = {
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
static struct PyMemberDef simplequeue_members[] = {
{"__weaklistoffset__", T_PYSSIZET, offsetof(simplequeueobject, weakreflist), READONLY},
{NULL},
};
static PyTypeObject PySimpleQueueType = { static PyType_Slot simplequeue_slots[] = {
PyVarObject_HEAD_INIT(NULL, 0) {Py_tp_dealloc, simplequeue_dealloc},
"_queue.SimpleQueue", /*tp_name*/ {Py_tp_doc, (void *)simplequeue_new__doc__},
sizeof(simplequeueobject), /*tp_basicsize*/ {Py_tp_traverse, simplequeue_traverse},
0, /*tp_itemsize*/ {Py_tp_members, simplequeue_members},
/* methods */ {Py_tp_methods, simplequeue_methods},
(destructor)simplequeue_dealloc, /*tp_dealloc*/ {Py_tp_new, simplequeue_new},
0, /*tp_vectorcall_offset*/ {0, NULL},
0, /*tp_getattr*/ };
0, /*tp_setattr*/
0, /*tp_as_async*/ static PyType_Spec simplequeue_spec = {
0, /*tp_repr*/ .name = "_queue.SimpleQueue",
0, /*tp_as_number*/ .basicsize = sizeof(simplequeueobject),
0, /*tp_as_sequence*/ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
0, /*tp_as_mapping*/ .slots = simplequeue_slots,
0, /*tp_hash*/
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
| Py_TPFLAGS_HAVE_GC, /* tp_flags */
simplequeue_new__doc__, /*tp_doc*/
(traverseproc)simplequeue_traverse, /*tp_traverse*/
0, /*tp_clear*/
0, /*tp_richcompare*/
offsetof(simplequeueobject, weakreflist), /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
simplequeue_methods, /*tp_methods*/
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
simplequeue_new /* tp_new */
}; };
@ -358,15 +382,13 @@ PyDoc_STRVAR(queue_module_doc,
This module is an implementation detail, please do not use it directly."); This module is an implementation detail, please do not use it directly.");
static struct PyModuleDef queuemodule = { static struct PyModuleDef queuemodule = {
PyModuleDef_HEAD_INIT, .m_base = PyModuleDef_HEAD_INIT,
"_queue", .m_name = "_queue",
queue_module_doc, .m_doc = queue_module_doc,
-1, .m_size = sizeof(simplequeue_state),
NULL, .m_traverse = queue_traverse,
NULL, .m_clear = queue_clear,
NULL, .m_free = queue_free,
NULL,
NULL
}; };
@ -374,26 +396,40 @@ PyMODINIT_FUNC
PyInit__queue(void) PyInit__queue(void)
{ {
PyObject *m; PyObject *m;
simplequeue_state *state;
/* Create the module */ /* Create the module */
m = PyModule_Create(&queuemodule); m = PyModule_Create(&queuemodule);
if (m == NULL) if (m == NULL)
return NULL; return NULL;
EmptyError = PyErr_NewExceptionWithDoc( state = simplequeue_get_state(m);
state->EmptyError = PyErr_NewExceptionWithDoc(
"_queue.Empty", "_queue.Empty",
"Exception raised by Queue.get(block=0)/get_nowait().", "Exception raised by Queue.get(block=0)/get_nowait().",
NULL, NULL); NULL, NULL);
if (EmptyError == NULL) if (state->EmptyError == NULL)
return NULL; goto error;
Py_INCREF(EmptyError); Py_INCREF(state->EmptyError);
if (PyModule_AddObject(m, "Empty", EmptyError) < 0) if (PyModule_AddObject(m, "Empty", state->EmptyError) < 0) {
return NULL; Py_DECREF(state->EmptyError);
goto error;
}
if (PyModule_AddType(m, &PySimpleQueueType) < 0) { state->SimpleQueueType = (PyTypeObject *)PyType_FromModuleAndSpec(m,
return NULL; &simplequeue_spec,
NULL);
if (state->SimpleQueueType == NULL) {
goto error;
}
if (PyModule_AddType(m, state->SimpleQueueType) < 0) {
goto error;
} }
return m; return m;
error:
Py_DECREF(m);
return NULL;
} }

View File

@ -16,11 +16,11 @@ simplequeue_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
if ((type == &PySimpleQueueType) && if ((type == simplequeue_get_state_by_type(type)->SimpleQueueType) &&
!_PyArg_NoPositional("SimpleQueue", args)) { !_PyArg_NoPositional("SimpleQueue", args)) {
goto exit; goto exit;
} }
if ((type == &PySimpleQueueType) && if ((type == simplequeue_get_state_by_type(type)->SimpleQueueType) &&
!_PyArg_NoKeywords("SimpleQueue", kwargs)) { !_PyArg_NoKeywords("SimpleQueue", kwargs)) {
goto exit; goto exit;
} }
@ -133,42 +133,26 @@ PyDoc_STRVAR(_queue_SimpleQueue_get__doc__,
"in that case)."); "in that case).");
#define _QUEUE_SIMPLEQUEUE_GET_METHODDEF \ #define _QUEUE_SIMPLEQUEUE_GET_METHODDEF \
{"get", (PyCFunction)(void(*)(void))_queue_SimpleQueue_get, METH_FASTCALL|METH_KEYWORDS, _queue_SimpleQueue_get__doc__}, {"get", (PyCFunction)(void(*)(void))_queue_SimpleQueue_get, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _queue_SimpleQueue_get__doc__},
static PyObject * static PyObject *
_queue_SimpleQueue_get_impl(simplequeueobject *self, int block, _queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
PyObject *timeout); int block, PyObject *timeout);
static PyObject * static PyObject *
_queue_SimpleQueue_get(simplequeueobject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) _queue_SimpleQueue_get(simplequeueobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
static const char * const _keywords[] = {"block", "timeout", NULL}; static const char * const _keywords[] = {"block", "timeout", NULL};
static _PyArg_Parser _parser = {NULL, _keywords, "get", 0}; static _PyArg_Parser _parser = {"|pO:get", _keywords, 0};
PyObject *argsbuf[2];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
int block = 1; int block = 1;
PyObject *timeout = Py_None; PyObject *timeout = Py_None;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 2, 0, argsbuf); if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
if (!args) { &block, &timeout)) {
goto exit; goto exit;
} }
if (!noptargs) { return_value = _queue_SimpleQueue_get_impl(self, cls, block, timeout);
goto skip_optional_pos;
}
if (args[0]) {
block = PyObject_IsTrue(args[0]);
if (block < 0) {
goto exit;
}
if (!--noptargs) {
goto skip_optional_pos;
}
}
timeout = args[1];
skip_optional_pos:
return_value = _queue_SimpleQueue_get_impl(self, block, timeout);
exit: exit:
return return_value; return return_value;
@ -184,15 +168,27 @@ PyDoc_STRVAR(_queue_SimpleQueue_get_nowait__doc__,
"raise the Empty exception."); "raise the Empty exception.");
#define _QUEUE_SIMPLEQUEUE_GET_NOWAIT_METHODDEF \ #define _QUEUE_SIMPLEQUEUE_GET_NOWAIT_METHODDEF \
{"get_nowait", (PyCFunction)_queue_SimpleQueue_get_nowait, METH_NOARGS, _queue_SimpleQueue_get_nowait__doc__}, {"get_nowait", (PyCFunction)(void(*)(void))_queue_SimpleQueue_get_nowait, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _queue_SimpleQueue_get_nowait__doc__},
static PyObject * static PyObject *
_queue_SimpleQueue_get_nowait_impl(simplequeueobject *self); _queue_SimpleQueue_get_nowait_impl(simplequeueobject *self,
PyTypeObject *cls);
static PyObject * static PyObject *
_queue_SimpleQueue_get_nowait(simplequeueobject *self, PyObject *Py_UNUSED(ignored)) _queue_SimpleQueue_get_nowait(simplequeueobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{ {
return _queue_SimpleQueue_get_nowait_impl(self); PyObject *return_value = NULL;
static const char * const _keywords[] = { NULL};
static _PyArg_Parser _parser = {":get_nowait", _keywords, 0};
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser
)) {
goto exit;
}
return_value = _queue_SimpleQueue_get_nowait_impl(self, cls);
exit:
return return_value;
} }
PyDoc_STRVAR(_queue_SimpleQueue_empty__doc__, PyDoc_STRVAR(_queue_SimpleQueue_empty__doc__,
@ -250,4 +246,4 @@ _queue_SimpleQueue_qsize(simplequeueobject *self, PyObject *Py_UNUSED(ignored))
exit: exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=b4717e2974cbc909 input=a9049054013a1b77]*/ /*[clinic end generated code: output=ce56b46fac150909 input=a9049054013a1b77]*/