bpo-40077: Convert _queuemodule to use heap types (GH-23136)
@vstinner / @corona10, would you mind reviewing this?
This commit is contained in:
parent
8805a4dad2
commit
01c6aa43dc
|
@ -0,0 +1 @@
|
||||||
|
Convert :mod:`queue` to use heap types.
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]*/
|
||||||
|
|
Loading…
Reference in New Issue