1#ifndef Py_BUILD_CORE_BUILTIN 2# define Py_BUILD_CORE_MODULE 1 3#endif 4 5#include "Python.h" 6#include "pycore_moduleobject.h" // _PyModule_GetState() 7#include "structmember.h" // PyMemberDef 8#include <stddef.h> // offsetof() 9 10typedef struct { 11 PyTypeObject *SimpleQueueType; 12 PyObject *EmptyError; 13} simplequeue_state; 14 15static simplequeue_state * 16simplequeue_get_state(PyObject *module) 17{ 18 simplequeue_state *state = _PyModule_GetState(module); 19 assert(state); 20 return state; 21} 22static struct PyModuleDef queuemodule; 23#define simplequeue_get_state_by_type(type) \ 24 (simplequeue_get_state(PyType_GetModuleByDef(type, &queuemodule))) 25 26typedef struct { 27 PyObject_HEAD 28 PyThread_type_lock lock; 29 int locked; 30 PyObject *lst; 31 Py_ssize_t lst_pos; 32 PyObject *weakreflist; 33} simplequeueobject; 34 35/*[clinic input] 36module _queue 37class _queue.SimpleQueue "simplequeueobject *" "simplequeue_get_state_by_type(type)->SimpleQueueType" 38[clinic start generated code]*/ 39/*[clinic end generated code: output=da39a3ee5e6b4b0d input=0a4023fe4d198c8d]*/ 40 41static int 42simplequeue_clear(simplequeueobject *self) 43{ 44 Py_CLEAR(self->lst); 45 return 0; 46} 47 48static void 49simplequeue_dealloc(simplequeueobject *self) 50{ 51 PyTypeObject *tp = Py_TYPE(self); 52 53 PyObject_GC_UnTrack(self); 54 if (self->lock != NULL) { 55 /* Unlock the lock so it's safe to free it */ 56 if (self->locked > 0) 57 PyThread_release_lock(self->lock); 58 PyThread_free_lock(self->lock); 59 } 60 (void)simplequeue_clear(self); 61 if (self->weakreflist != NULL) 62 PyObject_ClearWeakRefs((PyObject *) self); 63 Py_TYPE(self)->tp_free(self); 64 Py_DECREF(tp); 65} 66 67static int 68simplequeue_traverse(simplequeueobject *self, visitproc visit, void *arg) 69{ 70 Py_VISIT(self->lst); 71 Py_VISIT(Py_TYPE(self)); 72 return 0; 73} 74 75/*[clinic input] 76@classmethod 77_queue.SimpleQueue.__new__ as simplequeue_new 78 79Simple, unbounded, reentrant FIFO queue. 80[clinic start generated code]*/ 81 82static PyObject * 83simplequeue_new_impl(PyTypeObject *type) 84/*[clinic end generated code: output=ba97740608ba31cd input=a0674a1643e3e2fb]*/ 85{ 86 simplequeueobject *self; 87 88 self = (simplequeueobject *) type->tp_alloc(type, 0); 89 if (self != NULL) { 90 self->weakreflist = NULL; 91 self->lst = PyList_New(0); 92 self->lock = PyThread_allocate_lock(); 93 self->lst_pos = 0; 94 if (self->lock == NULL) { 95 Py_DECREF(self); 96 PyErr_SetString(PyExc_MemoryError, "can't allocate lock"); 97 return NULL; 98 } 99 if (self->lst == NULL) { 100 Py_DECREF(self); 101 return NULL; 102 } 103 } 104 105 return (PyObject *) self; 106} 107 108/*[clinic input] 109_queue.SimpleQueue.put 110 item: object 111 block: bool = True 112 timeout: object = None 113 114Put the item on the queue. 115 116The optional 'block' and 'timeout' arguments are ignored, as this method 117never blocks. They are provided for compatibility with the Queue class. 118 119[clinic start generated code]*/ 120 121static PyObject * 122_queue_SimpleQueue_put_impl(simplequeueobject *self, PyObject *item, 123 int block, PyObject *timeout) 124/*[clinic end generated code: output=4333136e88f90d8b input=6e601fa707a782d5]*/ 125{ 126 /* BEGIN GIL-protected critical section */ 127 if (PyList_Append(self->lst, item) < 0) 128 return NULL; 129 if (self->locked) { 130 /* A get() may be waiting, wake it up */ 131 self->locked = 0; 132 PyThread_release_lock(self->lock); 133 } 134 /* END GIL-protected critical section */ 135 Py_RETURN_NONE; 136} 137 138/*[clinic input] 139_queue.SimpleQueue.put_nowait 140 item: object 141 142Put an item into the queue without blocking. 143 144This is exactly equivalent to `put(item)` and is only provided 145for compatibility with the Queue class. 146 147[clinic start generated code]*/ 148 149static PyObject * 150_queue_SimpleQueue_put_nowait_impl(simplequeueobject *self, PyObject *item) 151/*[clinic end generated code: output=0990536715efb1f1 input=36b1ea96756b2ece]*/ 152{ 153 return _queue_SimpleQueue_put_impl(self, item, 0, Py_None); 154} 155 156static PyObject * 157simplequeue_pop_item(simplequeueobject *self) 158{ 159 Py_ssize_t count, n; 160 PyObject *item; 161 162 n = PyList_GET_SIZE(self->lst); 163 assert(self->lst_pos < n); 164 165 item = PyList_GET_ITEM(self->lst, self->lst_pos); 166 Py_INCREF(Py_None); 167 PyList_SET_ITEM(self->lst, self->lst_pos, Py_None); 168 self->lst_pos += 1; 169 count = n - self->lst_pos; 170 if (self->lst_pos > count) { 171 /* The list is more than 50% empty, reclaim space at the beginning */ 172 if (PyList_SetSlice(self->lst, 0, self->lst_pos, NULL)) { 173 /* Undo pop */ 174 self->lst_pos -= 1; 175 PyList_SET_ITEM(self->lst, self->lst_pos, item); 176 return NULL; 177 } 178 self->lst_pos = 0; 179 } 180 return item; 181} 182 183/*[clinic input] 184_queue.SimpleQueue.get 185 186 cls: defining_class 187 / 188 block: bool = True 189 timeout as timeout_obj: object = None 190 191Remove and return an item from the queue. 192 193If optional args 'block' is true and 'timeout' is None (the default), 194block if necessary until an item is available. If 'timeout' is 195a non-negative number, it blocks at most 'timeout' seconds and raises 196the Empty exception if no item was available within that time. 197Otherwise ('block' is false), return an item if one is immediately 198available, else raise the Empty exception ('timeout' is ignored 199in that case). 200 201[clinic start generated code]*/ 202 203static PyObject * 204_queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls, 205 int block, PyObject *timeout_obj) 206/*[clinic end generated code: output=5c2cca914cd1e55b input=5b4047bfbc645ec1]*/ 207{ 208 _PyTime_t endtime = 0; 209 _PyTime_t timeout; 210 PyObject *item; 211 PyLockStatus r; 212 PY_TIMEOUT_T microseconds; 213 214 if (block == 0) { 215 /* Non-blocking */ 216 microseconds = 0; 217 } 218 else if (timeout_obj != Py_None) { 219 /* With timeout */ 220 if (_PyTime_FromSecondsObject(&timeout, 221 timeout_obj, _PyTime_ROUND_CEILING) < 0) { 222 return NULL; 223 } 224 if (timeout < 0) { 225 PyErr_SetString(PyExc_ValueError, 226 "'timeout' must be a non-negative number"); 227 return NULL; 228 } 229 microseconds = _PyTime_AsMicroseconds(timeout, 230 _PyTime_ROUND_CEILING); 231 if (microseconds > PY_TIMEOUT_MAX) { 232 PyErr_SetString(PyExc_OverflowError, 233 "timeout value is too large"); 234 return NULL; 235 } 236 endtime = _PyDeadline_Init(timeout); 237 } 238 else { 239 /* Infinitely blocking */ 240 microseconds = -1; 241 } 242 243 /* put() signals the queue to be non-empty by releasing the lock. 244 * So we simply try to acquire the lock in a loop, until the condition 245 * (queue non-empty) becomes true. 246 */ 247 while (self->lst_pos == PyList_GET_SIZE(self->lst)) { 248 /* First a simple non-blocking try without releasing the GIL */ 249 r = PyThread_acquire_lock_timed(self->lock, 0, 0); 250 if (r == PY_LOCK_FAILURE && microseconds != 0) { 251 Py_BEGIN_ALLOW_THREADS 252 r = PyThread_acquire_lock_timed(self->lock, microseconds, 1); 253 Py_END_ALLOW_THREADS 254 } 255 256 if (r == PY_LOCK_INTR && Py_MakePendingCalls() < 0) { 257 return NULL; 258 } 259 if (r == PY_LOCK_FAILURE) { 260 PyObject *module = PyType_GetModule(cls); 261 simplequeue_state *state = simplequeue_get_state(module); 262 /* Timed out */ 263 PyErr_SetNone(state->EmptyError); 264 return NULL; 265 } 266 self->locked = 1; 267 268 /* Adjust timeout for next iteration (if any) */ 269 if (microseconds > 0) { 270 timeout = _PyDeadline_Get(endtime); 271 microseconds = _PyTime_AsMicroseconds(timeout, 272 _PyTime_ROUND_CEILING); 273 } 274 } 275 276 /* BEGIN GIL-protected critical section */ 277 assert(self->lst_pos < PyList_GET_SIZE(self->lst)); 278 item = simplequeue_pop_item(self); 279 if (self->locked) { 280 PyThread_release_lock(self->lock); 281 self->locked = 0; 282 } 283 /* END GIL-protected critical section */ 284 285 return item; 286} 287 288/*[clinic input] 289_queue.SimpleQueue.get_nowait 290 291 cls: defining_class 292 / 293 294Remove and return an item from the queue without blocking. 295 296Only get an item if one is immediately available. Otherwise 297raise the Empty exception. 298[clinic start generated code]*/ 299 300static PyObject * 301_queue_SimpleQueue_get_nowait_impl(simplequeueobject *self, 302 PyTypeObject *cls) 303/*[clinic end generated code: output=620c58e2750f8b8a input=842f732bf04216d3]*/ 304{ 305 return _queue_SimpleQueue_get_impl(self, cls, 0, Py_None); 306} 307 308/*[clinic input] 309_queue.SimpleQueue.empty -> bool 310 311Return True if the queue is empty, False otherwise (not reliable!). 312[clinic start generated code]*/ 313 314static int 315_queue_SimpleQueue_empty_impl(simplequeueobject *self) 316/*[clinic end generated code: output=1a02a1b87c0ef838 input=1a98431c45fd66f9]*/ 317{ 318 return self->lst_pos == PyList_GET_SIZE(self->lst); 319} 320 321/*[clinic input] 322_queue.SimpleQueue.qsize -> Py_ssize_t 323 324Return the approximate size of the queue (not reliable!). 325[clinic start generated code]*/ 326 327static Py_ssize_t 328_queue_SimpleQueue_qsize_impl(simplequeueobject *self) 329/*[clinic end generated code: output=f9dcd9d0a90e121e input=7a74852b407868a1]*/ 330{ 331 return PyList_GET_SIZE(self->lst) - self->lst_pos; 332} 333 334static int 335queue_traverse(PyObject *m, visitproc visit, void *arg) 336{ 337 simplequeue_state *state = simplequeue_get_state(m); 338 Py_VISIT(state->SimpleQueueType); 339 Py_VISIT(state->EmptyError); 340 return 0; 341} 342 343static int 344queue_clear(PyObject *m) 345{ 346 simplequeue_state *state = simplequeue_get_state(m); 347 Py_CLEAR(state->SimpleQueueType); 348 Py_CLEAR(state->EmptyError); 349 return 0; 350} 351 352static void 353queue_free(void *m) 354{ 355 queue_clear((PyObject *)m); 356} 357 358#include "clinic/_queuemodule.c.h" 359 360 361static PyMethodDef simplequeue_methods[] = { 362 _QUEUE_SIMPLEQUEUE_EMPTY_METHODDEF 363 _QUEUE_SIMPLEQUEUE_GET_METHODDEF 364 _QUEUE_SIMPLEQUEUE_GET_NOWAIT_METHODDEF 365 _QUEUE_SIMPLEQUEUE_PUT_METHODDEF 366 _QUEUE_SIMPLEQUEUE_PUT_NOWAIT_METHODDEF 367 _QUEUE_SIMPLEQUEUE_QSIZE_METHODDEF 368 {"__class_getitem__", Py_GenericAlias, 369 METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, 370 {NULL, NULL} /* sentinel */ 371}; 372 373static struct PyMemberDef simplequeue_members[] = { 374 {"__weaklistoffset__", T_PYSSIZET, offsetof(simplequeueobject, weakreflist), READONLY}, 375 {NULL}, 376}; 377 378static PyType_Slot simplequeue_slots[] = { 379 {Py_tp_dealloc, simplequeue_dealloc}, 380 {Py_tp_doc, (void *)simplequeue_new__doc__}, 381 {Py_tp_traverse, simplequeue_traverse}, 382 {Py_tp_clear, simplequeue_clear}, 383 {Py_tp_members, simplequeue_members}, 384 {Py_tp_methods, simplequeue_methods}, 385 {Py_tp_new, simplequeue_new}, 386 {0, NULL}, 387}; 388 389static PyType_Spec simplequeue_spec = { 390 .name = "_queue.SimpleQueue", 391 .basicsize = sizeof(simplequeueobject), 392 .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | 393 Py_TPFLAGS_IMMUTABLETYPE), 394 .slots = simplequeue_slots, 395}; 396 397 398/* Initialization function */ 399 400PyDoc_STRVAR(queue_module_doc, 401"C implementation of the Python queue module.\n\ 402This module is an implementation detail, please do not use it directly."); 403 404static int 405queuemodule_exec(PyObject *module) 406{ 407 simplequeue_state *state = simplequeue_get_state(module); 408 409 state->EmptyError = PyErr_NewExceptionWithDoc( 410 "_queue.Empty", 411 "Exception raised by Queue.get(block=0)/get_nowait().", 412 NULL, NULL); 413 if (state->EmptyError == NULL) { 414 return -1; 415 } 416 if (PyModule_AddObjectRef(module, "Empty", state->EmptyError) < 0) { 417 return -1; 418 } 419 420 state->SimpleQueueType = (PyTypeObject *)PyType_FromModuleAndSpec( 421 module, &simplequeue_spec, NULL); 422 if (state->SimpleQueueType == NULL) { 423 return -1; 424 } 425 if (PyModule_AddType(module, state->SimpleQueueType) < 0) { 426 return -1; 427 } 428 429 return 0; 430} 431 432static PyModuleDef_Slot queuemodule_slots[] = { 433 {Py_mod_exec, queuemodule_exec}, 434 {0, NULL} 435}; 436 437 438static struct PyModuleDef queuemodule = { 439 .m_base = PyModuleDef_HEAD_INIT, 440 .m_name = "_queue", 441 .m_doc = queue_module_doc, 442 .m_size = sizeof(simplequeue_state), 443 .m_slots = queuemodule_slots, 444 .m_traverse = queue_traverse, 445 .m_clear = queue_clear, 446 .m_free = queue_free, 447}; 448 449 450PyMODINIT_FUNC 451PyInit__queue(void) 452{ 453 return PyModuleDef_Init(&queuemodule); 454} 455