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 "structmember.h" // PyMemberDef
#include <stddef.h> // offsetof()
/*[clinic input]
module _queue
class _queue.SimpleQueue "simplequeueobject *" "&PySimpleQueueType"
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=cf49af81bcbbbea6]*/
static PyTypeObject PySimpleQueueType; /* forward decl */
static PyObject *EmptyError;
typedef struct {
PyTypeObject *SimpleQueueType;
PyObject *EmptyError;
} simplequeue_state;
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 {
PyObject_HEAD
@ -21,10 +27,17 @@ typedef struct {
PyObject *weakreflist;
} 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
simplequeue_dealloc(simplequeueobject *self)
{
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
if (self->lock != NULL) {
/* Unlock the lock so it's safe to free it */
@ -36,6 +49,7 @@ simplequeue_dealloc(simplequeueobject *self)
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) self);
Py_TYPE(self)->tp_free(self);
Py_DECREF(tp);
}
static int
@ -155,6 +169,9 @@ simplequeue_pop_item(simplequeueobject *self)
/*[clinic input]
_queue.SimpleQueue.get
cls: defining_class
/
block: bool = True
timeout: object = None
@ -171,9 +188,9 @@ in that case).
[clinic start generated code]*/
static PyObject *
_queue_SimpleQueue_get_impl(simplequeueobject *self, int block,
PyObject *timeout)
/*[clinic end generated code: output=ec82a7157dcccd1a input=4bf691f9f01fa297]*/
_queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
int block, PyObject *timeout)
/*[clinic end generated code: output=1969aefa7db63666 input=5fc4d56b9a54757e]*/
{
_PyTime_t endtime = 0;
_PyTime_t timeout_val;
@ -225,8 +242,10 @@ _queue_SimpleQueue_get_impl(simplequeueobject *self, int block,
return NULL;
}
if (r == PY_LOCK_FAILURE) {
PyObject *module = PyType_GetModule(cls);
simplequeue_state *state = simplequeue_get_state(module);
/* Timed out */
PyErr_SetNone(EmptyError);
PyErr_SetNone(state->EmptyError);
return NULL;
}
self->locked = 1;
@ -251,6 +270,9 @@ _queue_SimpleQueue_get_impl(simplequeueobject *self, int block,
/*[clinic input]
_queue.SimpleQueue.get_nowait
cls: defining_class
/
Remove and return an item from the queue without blocking.
Only get an item if one is immediately available. Otherwise
@ -258,10 +280,11 @@ raise the Empty exception.
[clinic start generated code]*/
static PyObject *
_queue_SimpleQueue_get_nowait_impl(simplequeueobject *self)
/*[clinic end generated code: output=a89731a75dbe4937 input=6fe5102db540a1b9]*/
_queue_SimpleQueue_get_nowait_impl(simplequeueobject *self,
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]
@ -290,6 +313,29 @@ _queue_SimpleQueue_qsize_impl(simplequeueobject *self)
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"
@ -306,48 +352,26 @@ static PyMethodDef simplequeue_methods[] = {
{NULL, NULL} /* sentinel */
};
static struct PyMemberDef simplequeue_members[] = {
{"__weaklistoffset__", T_PYSSIZET, offsetof(simplequeueobject, weakreflist), READONLY},
{NULL},
};
static PyTypeObject PySimpleQueueType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_queue.SimpleQueue", /*tp_name*/
sizeof(simplequeueobject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)simplequeue_dealloc, /*tp_dealloc*/
0, /*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*/
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 */
static PyType_Slot simplequeue_slots[] = {
{Py_tp_dealloc, simplequeue_dealloc},
{Py_tp_doc, (void *)simplequeue_new__doc__},
{Py_tp_traverse, simplequeue_traverse},
{Py_tp_members, simplequeue_members},
{Py_tp_methods, simplequeue_methods},
{Py_tp_new, simplequeue_new},
{0, NULL},
};
static PyType_Spec simplequeue_spec = {
.name = "_queue.SimpleQueue",
.basicsize = sizeof(simplequeueobject),
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
.slots = simplequeue_slots,
};
@ -358,15 +382,13 @@ PyDoc_STRVAR(queue_module_doc,
This module is an implementation detail, please do not use it directly.");
static struct PyModuleDef queuemodule = {
PyModuleDef_HEAD_INIT,
"_queue",
queue_module_doc,
-1,
NULL,
NULL,
NULL,
NULL,
NULL
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "_queue",
.m_doc = queue_module_doc,
.m_size = sizeof(simplequeue_state),
.m_traverse = queue_traverse,
.m_clear = queue_clear,
.m_free = queue_free,
};
@ -374,26 +396,40 @@ PyMODINIT_FUNC
PyInit__queue(void)
{
PyObject *m;
simplequeue_state *state;
/* Create the module */
m = PyModule_Create(&queuemodule);
if (m == NULL)
return NULL;
EmptyError = PyErr_NewExceptionWithDoc(
state = simplequeue_get_state(m);
state->EmptyError = PyErr_NewExceptionWithDoc(
"_queue.Empty",
"Exception raised by Queue.get(block=0)/get_nowait().",
NULL, NULL);
if (EmptyError == NULL)
return NULL;
if (state->EmptyError == NULL)
goto error;
Py_INCREF(EmptyError);
if (PyModule_AddObject(m, "Empty", EmptyError) < 0)
return NULL;
Py_INCREF(state->EmptyError);
if (PyModule_AddObject(m, "Empty", state->EmptyError) < 0) {
Py_DECREF(state->EmptyError);
goto error;
}
if (PyModule_AddType(m, &PySimpleQueueType) < 0) {
return NULL;
state->SimpleQueueType = (PyTypeObject *)PyType_FromModuleAndSpec(m,
&simplequeue_spec,
NULL);
if (state->SimpleQueueType == NULL) {
goto error;
}
if (PyModule_AddType(m, state->SimpleQueueType) < 0) {
goto error;
}
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;
if ((type == &PySimpleQueueType) &&
if ((type == simplequeue_get_state_by_type(type)->SimpleQueueType) &&
!_PyArg_NoPositional("SimpleQueue", args)) {
goto exit;
}
if ((type == &PySimpleQueueType) &&
if ((type == simplequeue_get_state_by_type(type)->SimpleQueueType) &&
!_PyArg_NoKeywords("SimpleQueue", kwargs)) {
goto exit;
}
@ -133,42 +133,26 @@ PyDoc_STRVAR(_queue_SimpleQueue_get__doc__,
"in that case).");
#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 *
_queue_SimpleQueue_get_impl(simplequeueobject *self, int block,
PyObject *timeout);
_queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
int block, PyObject *timeout);
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;
static const char * const _keywords[] = {"block", "timeout", NULL};
static _PyArg_Parser _parser = {NULL, _keywords, "get", 0};
PyObject *argsbuf[2];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0;
static _PyArg_Parser _parser = {"|pO:get", _keywords, 0};
int block = 1;
PyObject *timeout = Py_None;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 2, 0, argsbuf);
if (!args) {
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&block, &timeout)) {
goto exit;
}
if (!noptargs) {
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);
return_value = _queue_SimpleQueue_get_impl(self, cls, block, timeout);
exit:
return return_value;
@ -184,15 +168,27 @@ PyDoc_STRVAR(_queue_SimpleQueue_get_nowait__doc__,
"raise the Empty exception.");
#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 *
_queue_SimpleQueue_get_nowait_impl(simplequeueobject *self);
_queue_SimpleQueue_get_nowait_impl(simplequeueobject *self,
PyTypeObject *cls);
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__,
@ -250,4 +246,4 @@ _queue_SimpleQueue_qsize(simplequeueobject *self, PyObject *Py_UNUSED(ignored))
exit:
return return_value;
}
/*[clinic end generated code: output=b4717e2974cbc909 input=a9049054013a1b77]*/
/*[clinic end generated code: output=ce56b46fac150909 input=a9049054013a1b77]*/