#ifndef Py_BUILD_CORE_BUILTIN
# define Py_BUILD_CORE_MODULE 1
#endif
#include "Python.h"
#include "pycore_moduleobject.h"
#include "pycore_time.h"
#include "structmember.h"
#include <stddef.h>
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(type) \
(simplequeue_get_state(PyType_GetModuleByDef(type, &queuemodule)))
typedef struct {
PyObject_HEAD
PyThread_type_lock lock;
int locked;
PyObject *lst;
Py_ssize_t lst_pos;
PyObject *weakreflist;
} simplequeueobject;
static int
simplequeue_clear(simplequeueobject *self)
{
Py_CLEAR(self->lst);
return 0;
}
static void
simplequeue_dealloc(simplequeueobject *self)
{
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
if (self->lock != NULL) {
if (self->locked > 0)
PyThread_release_lock(self->lock);
PyThread_free_lock(self->lock);
}
(void)simplequeue_clear(self);
if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) self);
Py_TYPE(self)->tp_free(self);
Py_DECREF(tp);
}
static int
simplequeue_traverse(simplequeueobject *self, visitproc visit, void *arg)
{
Py_VISIT(self->lst);
Py_VISIT(Py_TYPE(self));
return 0;
}
static PyObject *
simplequeue_new_impl(PyTypeObject *type)
{
simplequeueobject *self;
self = (simplequeueobject *) type->tp_alloc(type, 0);
if (self != NULL) {
self->weakreflist = NULL;
self->lst = PyList_New(0);
self->lock = PyThread_allocate_lock();
self->lst_pos = 0;
if (self->lock == NULL) {
Py_DECREF(self);
PyErr_SetString(PyExc_MemoryError, "can't allocate lock");
return NULL;
}
if (self->lst == NULL) {
Py_DECREF(self);
return NULL;
}
}
return (PyObject *) self;
}
static PyObject *
_queue_SimpleQueue_put_impl(simplequeueobject *self, PyObject *item,
int block, PyObject *timeout)
{
if (PyList_Append(self->lst, item) < 0)
return NULL;
if (self->locked) {
self->locked = 0;
PyThread_release_lock(self->lock);
}
Py_RETURN_NONE;
}
static PyObject *
_queue_SimpleQueue_put_nowait_impl(simplequeueobject *self, PyObject *item)
{
return _queue_SimpleQueue_put_impl(self, item, 0, Py_None);
}
static PyObject *
simplequeue_pop_item(simplequeueobject *self)
{
Py_ssize_t count, n;
PyObject *item;
n = PyList_GET_SIZE(self->lst);
assert(self->lst_pos < n);
item = PyList_GET_ITEM(self->lst, self->lst_pos);
Py_INCREF(Py_None);
PyList_SET_ITEM(self->lst, self->lst_pos, Py_None);
self->lst_pos += 1;
count = n - self->lst_pos;
if (self->lst_pos > count) {
if (PyList_SetSlice(self->lst, 0, self->lst_pos, NULL)) {
self->lst_pos -= 1;
PyList_SET_ITEM(self->lst, self->lst_pos, item);
return NULL;
}
self->lst_pos = 0;
}
return item;
}
static PyObject *
_queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
int block, PyObject *timeout_obj)
{
_PyTime_t endtime = 0;
_PyTime_t timeout;
PyObject *item;
PyLockStatus r;
PY_TIMEOUT_T microseconds;
PyThreadState *tstate = PyThreadState_Get();
if (block == 0) {
microseconds = 0;
}
else if (timeout_obj != Py_None) {
if (_PyTime_FromSecondsObject(&timeout,
timeout_obj, _PyTime_ROUND_CEILING) < 0) {
return NULL;
}
if (timeout < 0) {
PyErr_SetString(PyExc_ValueError,
"'timeout' must be a non-negative number");
return NULL;
}
microseconds = _PyTime_AsMicroseconds(timeout,
_PyTime_ROUND_CEILING);
if (microseconds > PY_TIMEOUT_MAX) {
PyErr_SetString(PyExc_OverflowError,
"timeout value is too large");
return NULL;
}
endtime = _PyDeadline_Init(timeout);
}
else {
microseconds = -1;
}
while (self->lst_pos == PyList_GET_SIZE(self->lst)) {
r = PyThread_acquire_lock_timed(self->lock, 0, 0);
if (r == PY_LOCK_FAILURE && microseconds != 0) {
Py_BEGIN_ALLOW_THREADS
r = PyThread_acquire_lock_timed(self->lock, microseconds, 1);
Py_END_ALLOW_THREADS
}
if (r == PY_LOCK_INTR && _PyEval_MakePendingCalls(tstate) < 0) {
return NULL;
}
if (r == PY_LOCK_FAILURE) {
PyObject *module = PyType_GetModule(cls);
simplequeue_state *state = simplequeue_get_state(module);
PyErr_SetNone(state->EmptyError);
return NULL;
}
self->locked = 1;
if (microseconds > 0) {
timeout = _PyDeadline_Get(endtime);
microseconds = _PyTime_AsMicroseconds(timeout,
_PyTime_ROUND_CEILING);
}
}
assert(self->lst_pos < PyList_GET_SIZE(self->lst));
item = simplequeue_pop_item(self);
if (self->locked) {
PyThread_release_lock(self->lock);
self->locked = 0;
}
return item;
}
static PyObject *
_queue_SimpleQueue_get_nowait_impl(simplequeueobject *self,
PyTypeObject *cls)
{
return _queue_SimpleQueue_get_impl(self, cls, 0, Py_None);
}
static int
_queue_SimpleQueue_empty_impl(simplequeueobject *self)
{
return self->lst_pos == PyList_GET_SIZE(self->lst);
}
static Py_ssize_t
_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"
static PyMethodDef simplequeue_methods[] = {
_QUEUE_SIMPLEQUEUE_EMPTY_METHODDEF
_QUEUE_SIMPLEQUEUE_GET_METHODDEF
_QUEUE_SIMPLEQUEUE_GET_NOWAIT_METHODDEF
_QUEUE_SIMPLEQUEUE_PUT_METHODDEF
_QUEUE_SIMPLEQUEUE_PUT_NOWAIT_METHODDEF
_QUEUE_SIMPLEQUEUE_QSIZE_METHODDEF
{"__class_getitem__", Py_GenericAlias,
METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
{NULL, NULL}
};
static struct PyMemberDef simplequeue_members[] = {
{"__weaklistoffset__", T_PYSSIZET, offsetof(simplequeueobject, weakreflist), READONLY},
{NULL},
};
static PyType_Slot simplequeue_slots[] = {
{Py_tp_dealloc, simplequeue_dealloc},
{Py_tp_doc, (void *)simplequeue_new__doc__},
{Py_tp_traverse, simplequeue_traverse},
{Py_tp_clear, simplequeue_clear},
{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 |
Py_TPFLAGS_IMMUTABLETYPE),
.slots = simplequeue_slots,
};
PyDoc_STRVAR(queue_module_doc,
"C implementation of the Python queue module.\n\
This module is an implementation detail, please do not use it directly.");
static int
queuemodule_exec(PyObject *module)
{
simplequeue_state *state = simplequeue_get_state(module);
state->EmptyError = PyErr_NewExceptionWithDoc(
"_queue.Empty",
"Exception raised by Queue.get(block=0)/get_nowait().",
NULL, NULL);
if (state->EmptyError == NULL) {
return -1;
}
if (PyModule_AddObjectRef(module, "Empty", state->EmptyError) < 0) {
return -1;
}
state->SimpleQueueType = (PyTypeObject *)PyType_FromModuleAndSpec(
module, &simplequeue_spec, NULL);
if (state->SimpleQueueType == NULL) {
return -1;
}
if (PyModule_AddType(module, state->SimpleQueueType) < 0) {
return -1;
}
return 0;
}
static PyModuleDef_Slot queuemodule_slots[] = {
{Py_mod_exec, queuemodule_exec},
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
{0, NULL}
};
static struct PyModuleDef queuemodule = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "_queue",
.m_doc = queue_module_doc,
.m_size = sizeof(simplequeue_state),
.m_slots = queuemodule_slots,
.m_traverse = queue_traverse,
.m_clear = queue_clear,
.m_free = queue_free,
};
PyMODINIT_FUNC
PyInit__queue(void)
{
return PyModuleDef_Init(&queuemodule);
}