Skip to content

Commit 01c6aa4

Browse files
author
Erlend Egeberg Aasland
authored
bpo-40077: Convert _queuemodule to use heap types (GH-23136)
@vstinner / @corona10, would you mind reviewing this?
1 parent 8805a4d commit 01c6aa4

File tree

3 files changed

+138
-105
lines changed

3 files changed

+138
-105
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Convert :mod:`queue` to use heap types.

Modules/_queuemodule.c

Lines changed: 110 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
#include "Python.h"
2+
#include "structmember.h" // PyMemberDef
23
#include <stddef.h> // offsetof()
34

4-
/*[clinic input]
5-
module _queue
6-
class _queue.SimpleQueue "simplequeueobject *" "&PySimpleQueueType"
7-
[clinic start generated code]*/
8-
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=cf49af81bcbbbea6]*/
9-
10-
static PyTypeObject PySimpleQueueType; /* forward decl */
11-
12-
static PyObject *EmptyError;
5+
typedef struct {
6+
PyTypeObject *SimpleQueueType;
7+
PyObject *EmptyError;
8+
} simplequeue_state;
139

10+
static simplequeue_state *
11+
simplequeue_get_state(PyObject *module)
12+
{
13+
simplequeue_state *state = PyModule_GetState(module);
14+
assert(state);
15+
return state;
16+
}
17+
static struct PyModuleDef queuemodule;
18+
#define simplequeue_get_state_by_type(tp) \
19+
(simplequeue_get_state(_PyType_GetModuleByDef(type, &queuemodule)))
1420

1521
typedef struct {
1622
PyObject_HEAD
@@ -21,10 +27,17 @@ typedef struct {
2127
PyObject *weakreflist;
2228
} simplequeueobject;
2329

30+
/*[clinic input]
31+
module _queue
32+
class _queue.SimpleQueue "simplequeueobject *" "simplequeue_get_state_by_type(type)->SimpleQueueType"
33+
[clinic start generated code]*/
34+
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=0a4023fe4d198c8d]*/
2435

2536
static void
2637
simplequeue_dealloc(simplequeueobject *self)
2738
{
39+
PyTypeObject *tp = Py_TYPE(self);
40+
2841
PyObject_GC_UnTrack(self);
2942
if (self->lock != NULL) {
3043
/* Unlock the lock so it's safe to free it */
@@ -36,6 +49,7 @@ simplequeue_dealloc(simplequeueobject *self)
3649
if (self->weakreflist != NULL)
3750
PyObject_ClearWeakRefs((PyObject *) self);
3851
Py_TYPE(self)->tp_free(self);
52+
Py_DECREF(tp);
3953
}
4054

4155
static int
@@ -155,6 +169,9 @@ simplequeue_pop_item(simplequeueobject *self)
155169

156170
/*[clinic input]
157171
_queue.SimpleQueue.get
172+
173+
cls: defining_class
174+
/
158175
block: bool = True
159176
timeout: object = None
160177
@@ -171,9 +188,9 @@ in that case).
171188
[clinic start generated code]*/
172189

173190
static PyObject *
174-
_queue_SimpleQueue_get_impl(simplequeueobject *self, int block,
175-
PyObject *timeout)
176-
/*[clinic end generated code: output=ec82a7157dcccd1a input=4bf691f9f01fa297]*/
191+
_queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
192+
int block, PyObject *timeout)
193+
/*[clinic end generated code: output=1969aefa7db63666 input=5fc4d56b9a54757e]*/
177194
{
178195
_PyTime_t endtime = 0;
179196
_PyTime_t timeout_val;
@@ -225,8 +242,10 @@ _queue_SimpleQueue_get_impl(simplequeueobject *self, int block,
225242
return NULL;
226243
}
227244
if (r == PY_LOCK_FAILURE) {
245+
PyObject *module = PyType_GetModule(cls);
246+
simplequeue_state *state = simplequeue_get_state(module);
228247
/* Timed out */
229-
PyErr_SetNone(EmptyError);
248+
PyErr_SetNone(state->EmptyError);
230249
return NULL;
231250
}
232251
self->locked = 1;
@@ -251,17 +270,21 @@ _queue_SimpleQueue_get_impl(simplequeueobject *self, int block,
251270
/*[clinic input]
252271
_queue.SimpleQueue.get_nowait
253272
273+
cls: defining_class
274+
/
275+
254276
Remove and return an item from the queue without blocking.
255277
256278
Only get an item if one is immediately available. Otherwise
257279
raise the Empty exception.
258280
[clinic start generated code]*/
259281

260282
static PyObject *
261-
_queue_SimpleQueue_get_nowait_impl(simplequeueobject *self)
262-
/*[clinic end generated code: output=a89731a75dbe4937 input=6fe5102db540a1b9]*/
283+
_queue_SimpleQueue_get_nowait_impl(simplequeueobject *self,
284+
PyTypeObject *cls)
285+
/*[clinic end generated code: output=620c58e2750f8b8a input=842f732bf04216d3]*/
263286
{
264-
return _queue_SimpleQueue_get_impl(self, 0, Py_None);
287+
return _queue_SimpleQueue_get_impl(self, cls, 0, Py_None);
265288
}
266289

267290
/*[clinic input]
@@ -290,6 +313,29 @@ _queue_SimpleQueue_qsize_impl(simplequeueobject *self)
290313
return PyList_GET_SIZE(self->lst) - self->lst_pos;
291314
}
292315

316+
static int
317+
queue_traverse(PyObject *m, visitproc visit, void *arg)
318+
{
319+
simplequeue_state *state = simplequeue_get_state(m);
320+
Py_VISIT(state->SimpleQueueType);
321+
Py_VISIT(state->EmptyError);
322+
return 0;
323+
}
324+
325+
static int
326+
queue_clear(PyObject *m)
327+
{
328+
simplequeue_state *state = simplequeue_get_state(m);
329+
Py_CLEAR(state->SimpleQueueType);
330+
Py_CLEAR(state->EmptyError);
331+
return 0;
332+
}
333+
334+
static void
335+
queue_free(void *m)
336+
{
337+
queue_clear((PyObject *)m);
338+
}
293339

294340
#include "clinic/_queuemodule.c.h"
295341

@@ -306,48 +352,26 @@ static PyMethodDef simplequeue_methods[] = {
306352
{NULL, NULL} /* sentinel */
307353
};
308354

355+
static struct PyMemberDef simplequeue_members[] = {
356+
{"__weaklistoffset__", T_PYSSIZET, offsetof(simplequeueobject, weakreflist), READONLY},
357+
{NULL},
358+
};
359+
360+
static PyType_Slot simplequeue_slots[] = {
361+
{Py_tp_dealloc, simplequeue_dealloc},
362+
{Py_tp_doc, (void *)simplequeue_new__doc__},
363+
{Py_tp_traverse, simplequeue_traverse},
364+
{Py_tp_members, simplequeue_members},
365+
{Py_tp_methods, simplequeue_methods},
366+
{Py_tp_new, simplequeue_new},
367+
{0, NULL},
368+
};
309369

310-
static PyTypeObject PySimpleQueueType = {
311-
PyVarObject_HEAD_INIT(NULL, 0)
312-
"_queue.SimpleQueue", /*tp_name*/
313-
sizeof(simplequeueobject), /*tp_basicsize*/
314-
0, /*tp_itemsize*/
315-
/* methods */
316-
(destructor)simplequeue_dealloc, /*tp_dealloc*/
317-
0, /*tp_vectorcall_offset*/
318-
0, /*tp_getattr*/
319-
0, /*tp_setattr*/
320-
0, /*tp_as_async*/
321-
0, /*tp_repr*/
322-
0, /*tp_as_number*/
323-
0, /*tp_as_sequence*/
324-
0, /*tp_as_mapping*/
325-
0, /*tp_hash*/
326-
0, /*tp_call*/
327-
0, /*tp_str*/
328-
0, /*tp_getattro*/
329-
0, /*tp_setattro*/
330-
0, /*tp_as_buffer*/
331-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
332-
| Py_TPFLAGS_HAVE_GC, /* tp_flags */
333-
simplequeue_new__doc__, /*tp_doc*/
334-
(traverseproc)simplequeue_traverse, /*tp_traverse*/
335-
0, /*tp_clear*/
336-
0, /*tp_richcompare*/
337-
offsetof(simplequeueobject, weakreflist), /*tp_weaklistoffset*/
338-
0, /*tp_iter*/
339-
0, /*tp_iternext*/
340-
simplequeue_methods, /*tp_methods*/
341-
0, /* tp_members */
342-
0, /* tp_getset */
343-
0, /* tp_base */
344-
0, /* tp_dict */
345-
0, /* tp_descr_get */
346-
0, /* tp_descr_set */
347-
0, /* tp_dictoffset */
348-
0, /* tp_init */
349-
0, /* tp_alloc */
350-
simplequeue_new /* tp_new */
370+
static PyType_Spec simplequeue_spec = {
371+
.name = "_queue.SimpleQueue",
372+
.basicsize = sizeof(simplequeueobject),
373+
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
374+
.slots = simplequeue_slots,
351375
};
352376

353377

@@ -358,42 +382,54 @@ PyDoc_STRVAR(queue_module_doc,
358382
This module is an implementation detail, please do not use it directly.");
359383

360384
static struct PyModuleDef queuemodule = {
361-
PyModuleDef_HEAD_INIT,
362-
"_queue",
363-
queue_module_doc,
364-
-1,
365-
NULL,
366-
NULL,
367-
NULL,
368-
NULL,
369-
NULL
385+
.m_base = PyModuleDef_HEAD_INIT,
386+
.m_name = "_queue",
387+
.m_doc = queue_module_doc,
388+
.m_size = sizeof(simplequeue_state),
389+
.m_traverse = queue_traverse,
390+
.m_clear = queue_clear,
391+
.m_free = queue_free,
370392
};
371393

372394

373395
PyMODINIT_FUNC
374396
PyInit__queue(void)
375397
{
376398
PyObject *m;
399+
simplequeue_state *state;
377400

378401
/* Create the module */
379402
m = PyModule_Create(&queuemodule);
380403
if (m == NULL)
381404
return NULL;
382405

383-
EmptyError = PyErr_NewExceptionWithDoc(
406+
state = simplequeue_get_state(m);
407+
state->EmptyError = PyErr_NewExceptionWithDoc(
384408
"_queue.Empty",
385409
"Exception raised by Queue.get(block=0)/get_nowait().",
386410
NULL, NULL);
387-
if (EmptyError == NULL)
388-
return NULL;
411+
if (state->EmptyError == NULL)
412+
goto error;
389413

390-
Py_INCREF(EmptyError);
391-
if (PyModule_AddObject(m, "Empty", EmptyError) < 0)
392-
return NULL;
414+
Py_INCREF(state->EmptyError);
415+
if (PyModule_AddObject(m, "Empty", state->EmptyError) < 0) {
416+
Py_DECREF(state->EmptyError);
417+
goto error;
418+
}
393419

394-
if (PyModule_AddType(m, &PySimpleQueueType) < 0) {
395-
return NULL;
420+
state->SimpleQueueType = (PyTypeObject *)PyType_FromModuleAndSpec(m,
421+
&simplequeue_spec,
422+
NULL);
423+
if (state->SimpleQueueType == NULL) {
424+
goto error;
425+
}
426+
if (PyModule_AddType(m, state->SimpleQueueType) < 0) {
427+
goto error;
396428
}
397429

398430
return m;
431+
432+
error:
433+
Py_DECREF(m);
434+
return NULL;
399435
}

Modules/clinic/_queuemodule.c.h

Lines changed: 27 additions & 31 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)