| 
									
										
										
										
											2021-10-22 16:36:28 +03:00
										 |  |  | #ifndef Py_BUILD_CORE_BUILTIN
 | 
					
						
							|  |  |  | #  define Py_BUILD_CORE_MODULE 1
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | #include "Python.h"
 | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | #include "pycore_ceval.h"         // Py_MakePendingCalls()
 | 
					
						
							| 
									
										
										
										
											2021-04-22 00:52:52 +02:00
										 |  |  | #include "pycore_moduleobject.h"  // _PyModule_GetState()
 | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | #include "pycore_parking_lot.h"
 | 
					
						
							| 
									
										
										
										
											2024-02-21 00:31:30 +01:00
										 |  |  | #include "pycore_time.h"          // _PyTime_FromSecondsObject()
 | 
					
						
							| 
									
										
										
										
											2023-07-25 15:28:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 04:17:51 -08:00
										 |  |  | #include <stdbool.h>
 | 
					
						
							| 
									
										
										
										
											2020-04-15 02:35:41 +02:00
										 |  |  | #include <stddef.h>               // offsetof()
 | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  | typedef struct { | 
					
						
							|  |  |  |     PyTypeObject *SimpleQueueType; | 
					
						
							|  |  |  |     PyObject *EmptyError; | 
					
						
							|  |  |  | } simplequeue_state; | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  | static simplequeue_state * | 
					
						
							|  |  |  | simplequeue_get_state(PyObject *module) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-04-22 00:52:52 +02:00
										 |  |  |     simplequeue_state *state = _PyModule_GetState(module); | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  |     assert(state); | 
					
						
							|  |  |  |     return state; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | static struct PyModuleDef queuemodule; | 
					
						
							| 
									
										
										
										
											2020-12-28 18:47:16 +01:00
										 |  |  | #define simplequeue_get_state_by_type(type) \
 | 
					
						
							| 
									
										
										
										
											2022-02-11 17:22:11 +01:00
										 |  |  |     (simplequeue_get_state(PyType_GetModuleByDef(type, &queuemodule))) | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 04:17:51 -08:00
										 |  |  | static const Py_ssize_t INITIAL_RING_BUF_CAPACITY = 8; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							|  |  |  |     // Where to place the next item
 | 
					
						
							|  |  |  |     Py_ssize_t put_idx; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Where to get the next item
 | 
					
						
							|  |  |  |     Py_ssize_t get_idx; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyObject **items; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Total number of items that may be stored
 | 
					
						
							|  |  |  |     Py_ssize_t items_cap; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Number of items stored
 | 
					
						
							|  |  |  |     Py_ssize_t num_items; | 
					
						
							|  |  |  | } RingBuf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | RingBuf_Init(RingBuf *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     buf->put_idx = 0; | 
					
						
							|  |  |  |     buf->get_idx = 0; | 
					
						
							|  |  |  |     buf->items_cap = INITIAL_RING_BUF_CAPACITY; | 
					
						
							|  |  |  |     buf->num_items = 0; | 
					
						
							|  |  |  |     buf->items = PyMem_Calloc(buf->items_cap, sizeof(PyObject *)); | 
					
						
							|  |  |  |     if (buf->items == NULL) { | 
					
						
							|  |  |  |         PyErr_NoMemory(); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | RingBuf_At(RingBuf *buf, Py_ssize_t idx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(idx >= 0 && idx < buf->num_items); | 
					
						
							|  |  |  |     return buf->items[(buf->get_idx + idx) % buf->items_cap]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | RingBuf_Fini(RingBuf *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyObject **items = buf->items; | 
					
						
							|  |  |  |     Py_ssize_t num_items = buf->num_items; | 
					
						
							|  |  |  |     Py_ssize_t cap = buf->items_cap; | 
					
						
							|  |  |  |     Py_ssize_t idx = buf->get_idx; | 
					
						
							|  |  |  |     buf->items = NULL; | 
					
						
							|  |  |  |     buf->put_idx = 0; | 
					
						
							|  |  |  |     buf->get_idx = 0; | 
					
						
							|  |  |  |     buf->num_items = 0; | 
					
						
							|  |  |  |     buf->items_cap = 0; | 
					
						
							|  |  |  |     for (Py_ssize_t n = num_items; n > 0; idx = (idx + 1) % cap, n--) { | 
					
						
							|  |  |  |         Py_DECREF(items[idx]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     PyMem_Free(items); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Resize the underlying items array of buf to the new capacity and arrange
 | 
					
						
							|  |  |  | // the items contiguously in the new items array.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Returns -1 on allocation failure or 0 on success.
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | resize_ringbuf(RingBuf *buf, Py_ssize_t capacity) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Py_ssize_t new_capacity = Py_MAX(INITIAL_RING_BUF_CAPACITY, capacity); | 
					
						
							|  |  |  |     if (new_capacity == buf->items_cap) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     assert(buf->num_items <= new_capacity); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyObject **new_items = PyMem_Calloc(new_capacity, sizeof(PyObject *)); | 
					
						
							|  |  |  |     if (new_items == NULL) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Copy the "tail" of the old items array. This corresponds to "head" of
 | 
					
						
							|  |  |  |     // the abstract ring buffer.
 | 
					
						
							|  |  |  |     Py_ssize_t tail_size = | 
					
						
							|  |  |  |         Py_MIN(buf->num_items, buf->items_cap - buf->get_idx); | 
					
						
							|  |  |  |     if (tail_size > 0) { | 
					
						
							|  |  |  |         memcpy(new_items, buf->items + buf->get_idx, | 
					
						
							|  |  |  |                tail_size * sizeof(PyObject *)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Copy the "head" of the old items array, if any. This corresponds to the
 | 
					
						
							|  |  |  |     // "tail" of the abstract ring buffer.
 | 
					
						
							|  |  |  |     Py_ssize_t head_size = buf->num_items - tail_size; | 
					
						
							|  |  |  |     if (head_size > 0) { | 
					
						
							|  |  |  |         memcpy(new_items + tail_size, buf->items, | 
					
						
							|  |  |  |                head_size * sizeof(PyObject *)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyMem_Free(buf->items); | 
					
						
							|  |  |  |     buf->items = new_items; | 
					
						
							|  |  |  |     buf->items_cap = new_capacity; | 
					
						
							|  |  |  |     buf->get_idx = 0; | 
					
						
							|  |  |  |     buf->put_idx = buf->num_items; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Returns a strong reference from the head of the buffer.
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | RingBuf_Get(RingBuf *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(buf->num_items > 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (buf->num_items < (buf->items_cap / 4)) { | 
					
						
							|  |  |  |         // Items is less than 25% occupied, shrink it by 50%. This allows for
 | 
					
						
							|  |  |  |         // growth without immediately needing to resize the underlying items
 | 
					
						
							|  |  |  |         // array.
 | 
					
						
							|  |  |  |         //
 | 
					
						
							|  |  |  |         // It's safe it ignore allocation failures here; shrinking is an
 | 
					
						
							|  |  |  |         // optimization that isn't required for correctness.
 | 
					
						
							|  |  |  |         (void)resize_ringbuf(buf, buf->items_cap / 2); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyObject *item = buf->items[buf->get_idx]; | 
					
						
							|  |  |  |     buf->items[buf->get_idx] = NULL; | 
					
						
							|  |  |  |     buf->get_idx = (buf->get_idx + 1) % buf->items_cap; | 
					
						
							|  |  |  |     buf->num_items--; | 
					
						
							|  |  |  |     return item; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | // Returns 0 on success or -1 if the buffer failed to grow.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Steals a reference to item.
 | 
					
						
							| 
									
										
										
										
											2024-01-19 04:17:51 -08:00
										 |  |  | static int | 
					
						
							|  |  |  | RingBuf_Put(RingBuf *buf, PyObject *item) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(buf->num_items <= buf->items_cap); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (buf->num_items == buf->items_cap) { | 
					
						
							|  |  |  |         // Buffer is full, grow it.
 | 
					
						
							|  |  |  |         if (resize_ringbuf(buf, buf->items_cap * 2) < 0) { | 
					
						
							|  |  |  |             PyErr_NoMemory(); | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  |     buf->items[buf->put_idx] = item; | 
					
						
							| 
									
										
										
										
											2024-01-19 04:17:51 -08:00
										 |  |  |     buf->put_idx = (buf->put_idx + 1) % buf->items_cap; | 
					
						
							|  |  |  |     buf->num_items++; | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static Py_ssize_t | 
					
						
							|  |  |  | RingBuf_Len(RingBuf *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return buf->num_items; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool | 
					
						
							|  |  |  | RingBuf_IsEmpty(RingBuf *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return buf->num_items == 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | typedef struct { | 
					
						
							|  |  |  |     PyObject_HEAD | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Are there threads waiting for items
 | 
					
						
							|  |  |  |     bool has_threads_waiting; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Items in the queue
 | 
					
						
							| 
									
										
										
										
											2024-01-19 04:17:51 -08:00
										 |  |  |     RingBuf buf; | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  |     PyObject *weakreflist; | 
					
						
							|  |  |  | } simplequeueobject; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  | /*[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]*/ | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-27 17:50:12 +02:00
										 |  |  | static int | 
					
						
							|  |  |  | simplequeue_clear(simplequeueobject *self) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-01-19 04:17:51 -08:00
										 |  |  |     RingBuf_Fini(&self->buf); | 
					
						
							| 
									
										
										
										
											2021-05-27 17:50:12 +02:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | static void | 
					
						
							|  |  |  | simplequeue_dealloc(simplequeueobject *self) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  |     PyTypeObject *tp = Py_TYPE(self); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-13 12:52:18 +01:00
										 |  |  |     PyObject_GC_UnTrack(self); | 
					
						
							| 
									
										
										
										
											2021-05-27 17:50:12 +02:00
										 |  |  |     (void)simplequeue_clear(self); | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  |     if (self->weakreflist != NULL) | 
					
						
							|  |  |  |         PyObject_ClearWeakRefs((PyObject *) self); | 
					
						
							|  |  |  |     Py_TYPE(self)->tp_free(self); | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  |     Py_DECREF(tp); | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | simplequeue_traverse(simplequeueobject *self, visitproc visit, void *arg) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-01-19 04:17:51 -08:00
										 |  |  |     RingBuf *buf = &self->buf; | 
					
						
							|  |  |  |     for (Py_ssize_t i = 0, num_items = buf->num_items; i < num_items; i++) { | 
					
						
							|  |  |  |         Py_VISIT(RingBuf_At(buf, i)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-05-27 17:50:12 +02:00
										 |  |  |     Py_VISIT(Py_TYPE(self)); | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | @classmethod | 
					
						
							|  |  |  | _queue.SimpleQueue.__new__ as simplequeue_new | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Simple, unbounded, reentrant FIFO queue. | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | simplequeue_new_impl(PyTypeObject *type) | 
					
						
							|  |  |  | /*[clinic end generated code: output=ba97740608ba31cd input=a0674a1643e3e2fb]*/ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     simplequeueobject *self; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     self = (simplequeueobject *) type->tp_alloc(type, 0); | 
					
						
							|  |  |  |     if (self != NULL) { | 
					
						
							|  |  |  |         self->weakreflist = NULL; | 
					
						
							| 
									
										
										
										
											2024-01-19 04:17:51 -08:00
										 |  |  |         if (RingBuf_Init(&self->buf) < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  |             Py_DECREF(self); | 
					
						
							|  |  |  |             return NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return (PyObject *) self; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | typedef struct { | 
					
						
							|  |  |  |     bool handed_off; | 
					
						
							|  |  |  |     simplequeueobject *queue; | 
					
						
							|  |  |  |     PyObject *item; | 
					
						
							|  |  |  | } HandoffData; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | maybe_handoff_item(HandoffData *data, PyObject **item, int has_more_waiters) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (item == NULL) { | 
					
						
							|  |  |  |         // No threads were waiting
 | 
					
						
							|  |  |  |         data->handed_off = false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         // There was at least one waiting thread, hand off the item
 | 
					
						
							|  |  |  |         *item = data->item; | 
					
						
							|  |  |  |         data->handed_off = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     data->queue->has_threads_waiting = has_more_waiters; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | /*[clinic input]
 | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | @critical_section | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | _queue.SimpleQueue.put | 
					
						
							|  |  |  |     item: object | 
					
						
							|  |  |  |     block: bool = True | 
					
						
							|  |  |  |     timeout: object = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Put the item on the queue. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The optional 'block' and 'timeout' arguments are ignored, as this method | 
					
						
							|  |  |  | never blocks.  They are provided for compatibility with the Queue class. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | _queue_SimpleQueue_put_impl(simplequeueobject *self, PyObject *item, | 
					
						
							|  |  |  |                             int block, PyObject *timeout) | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | /*[clinic end generated code: output=4333136e88f90d8b input=a16dbb33363c0fa8]*/ | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  |     HandoffData data = { | 
					
						
							|  |  |  |         .handed_off = 0, | 
					
						
							|  |  |  |         .item = Py_NewRef(item), | 
					
						
							|  |  |  |         .queue = self, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     if (self->has_threads_waiting) { | 
					
						
							|  |  |  |         // Try to hand the item off directly if there are threads waiting
 | 
					
						
							|  |  |  |         _PyParkingLot_Unpark(&self->has_threads_waiting, | 
					
						
							|  |  |  |                              (_Py_unpark_fn_t *)maybe_handoff_item, &data); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!data.handed_off) { | 
					
						
							|  |  |  |         if (RingBuf_Put(&self->buf, item) < 0) { | 
					
						
							|  |  |  |             return NULL; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     Py_RETURN_NONE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | @critical_section | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | _queue.SimpleQueue.put_nowait | 
					
						
							|  |  |  |     item: object | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Put an item into the queue without blocking. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This is exactly equivalent to `put(item)` and is only provided | 
					
						
							|  |  |  | for compatibility with the Queue class. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | _queue_SimpleQueue_put_nowait_impl(simplequeueobject *self, PyObject *item) | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | /*[clinic end generated code: output=0990536715efb1f1 input=ce949cc2cd8a4119]*/ | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     return _queue_SimpleQueue_put_impl(self, item, 0, Py_None); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | static PyObject * | 
					
						
							|  |  |  | empty_error(PyTypeObject *cls) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyObject *module = PyType_GetModule(cls); | 
					
						
							|  |  |  |     assert(module != NULL); | 
					
						
							|  |  |  |     simplequeue_state *state = simplequeue_get_state(module); | 
					
						
							|  |  |  |     PyErr_SetNone(state->EmptyError); | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | /*[clinic input]
 | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | @critical_section | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | _queue.SimpleQueue.get | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     cls: defining_class | 
					
						
							|  |  |  |     / | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  |     block: bool = True | 
					
						
							| 
									
										
										
										
											2021-10-01 13:29:25 +02:00
										 |  |  |     timeout as timeout_obj: object = None | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | Remove and return an item from the queue. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If optional args 'block' is true and 'timeout' is None (the default), | 
					
						
							|  |  |  | block if necessary until an item is available. If 'timeout' is | 
					
						
							|  |  |  | a non-negative number, it blocks at most 'timeout' seconds and raises | 
					
						
							|  |  |  | the Empty exception if no item was available within that time. | 
					
						
							|  |  |  | Otherwise ('block' is false), return an item if one is immediately | 
					
						
							|  |  |  | available, else raise the Empty exception ('timeout' is ignored | 
					
						
							|  |  |  | in that case). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  | _queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls, | 
					
						
							| 
									
										
										
										
											2021-10-01 13:29:25 +02:00
										 |  |  |                             int block, PyObject *timeout_obj) | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | /*[clinic end generated code: output=5c2cca914cd1e55b input=f7836c65e5839c51]*/ | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-02-20 16:02:27 +01:00
										 |  |  |     PyTime_t endtime = 0; | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-17 17:05:49 -06:00
										 |  |  |     // XXX Use PyThread_ParseTimeoutArg().
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  |     if (block != 0 && !Py_IsNone(timeout_obj)) { | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  |         /* With timeout */ | 
					
						
							| 
									
										
										
										
											2024-02-20 16:02:27 +01:00
										 |  |  |         PyTime_t timeout; | 
					
						
							| 
									
										
										
										
											2021-10-01 13:29:25 +02:00
										 |  |  |         if (_PyTime_FromSecondsObject(&timeout, | 
					
						
							|  |  |  |                                       timeout_obj, _PyTime_ROUND_CEILING) < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  |             return NULL; | 
					
						
							| 
									
										
										
										
											2021-10-01 13:29:25 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (timeout < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  |             PyErr_SetString(PyExc_ValueError, | 
					
						
							|  |  |  |                             "'timeout' must be a non-negative number"); | 
					
						
							|  |  |  |             return NULL; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-01 13:29:25 +02:00
										 |  |  |         endtime = _PyDeadline_Init(timeout); | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  |     for (;;) { | 
					
						
							|  |  |  |         if (!RingBuf_IsEmpty(&self->buf)) { | 
					
						
							|  |  |  |             return RingBuf_Get(&self->buf); | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-01 13:29:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  |         if (!block) { | 
					
						
							|  |  |  |             return empty_error(cls); | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-01 13:29:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  |         int64_t timeout_ns = -1; | 
					
						
							|  |  |  |         if (endtime != 0) { | 
					
						
							|  |  |  |             timeout_ns = _PyDeadline_Get(endtime); | 
					
						
							|  |  |  |             if (timeout_ns < 0) { | 
					
						
							|  |  |  |                 return empty_error(cls); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-01 13:29:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  |         bool waiting = 1; | 
					
						
							|  |  |  |         self->has_threads_waiting = waiting; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         PyObject *item = NULL; | 
					
						
							|  |  |  |         int st = _PyParkingLot_Park(&self->has_threads_waiting, &waiting, | 
					
						
							|  |  |  |                                     sizeof(bool), timeout_ns, &item, | 
					
						
							|  |  |  |                                     /* detach */ 1); | 
					
						
							|  |  |  |         switch (st) { | 
					
						
							|  |  |  |             case Py_PARK_OK: { | 
					
						
							|  |  |  |                 assert(item != NULL); | 
					
						
							|  |  |  |                 return item; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             case Py_PARK_TIMEOUT: { | 
					
						
							|  |  |  |                 return empty_error(cls); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             case Py_PARK_INTR: { | 
					
						
							|  |  |  |                 // Interrupted
 | 
					
						
							|  |  |  |                 if (Py_MakePendingCalls() < 0) { | 
					
						
							|  |  |  |                     return NULL; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             case Py_PARK_AGAIN: { | 
					
						
							|  |  |  |                 // This should be impossible with the current implementation of
 | 
					
						
							|  |  |  |                 // PyParkingLot, but would be possible if critical sections /
 | 
					
						
							|  |  |  |                 // the GIL were released before the thread was added to the
 | 
					
						
							|  |  |  |                 // internal thread queue in the parking lot.
 | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             default: { | 
					
						
							|  |  |  |                 Py_UNREACHABLE(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | @critical_section | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | _queue.SimpleQueue.get_nowait | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  |     cls: defining_class | 
					
						
							|  |  |  |     / | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | Remove and return an item from the queue without blocking. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Only get an item if one is immediately available. Otherwise | 
					
						
							|  |  |  | raise the Empty exception. | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  | _queue_SimpleQueue_get_nowait_impl(simplequeueobject *self, | 
					
						
							|  |  |  |                                    PyTypeObject *cls) | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | /*[clinic end generated code: output=620c58e2750f8b8a input=d48be63633fefae9]*/ | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  |     return _queue_SimpleQueue_get_impl(self, cls, 0, Py_None); | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | @critical_section | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | _queue.SimpleQueue.empty -> bool | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Return True if the queue is empty, False otherwise (not reliable!). | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | _queue_SimpleQueue_empty_impl(simplequeueobject *self) | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | /*[clinic end generated code: output=1a02a1b87c0ef838 input=96cb22df5a67d831]*/ | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-01-19 04:17:51 -08:00
										 |  |  |     return RingBuf_IsEmpty(&self->buf); | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | @critical_section | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | _queue.SimpleQueue.qsize -> Py_ssize_t | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Return the approximate size of the queue (not reliable!). | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static Py_ssize_t | 
					
						
							|  |  |  | _queue_SimpleQueue_qsize_impl(simplequeueobject *self) | 
					
						
							| 
									
										
										
										
											2024-01-23 11:25:41 -08:00
										 |  |  | /*[clinic end generated code: output=f9dcd9d0a90e121e input=e218623cb8c16a79]*/ | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-01-19 04:17:51 -08:00
										 |  |  |     return RingBuf_Len(&self->buf); | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  | 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); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #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 | 
					
						
							| 
									
										
										
										
											2021-09-19 18:05:30 +03:00
										 |  |  |     {"__class_getitem__",    Py_GenericAlias, | 
					
						
							| 
									
										
										
										
											2020-04-10 17:46:36 +03:00
										 |  |  |     METH_O|METH_CLASS,       PyDoc_STR("See PEP 585")}, | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  |     {NULL,           NULL}              /* sentinel */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  | static struct PyMemberDef simplequeue_members[] = { | 
					
						
							| 
									
										
										
										
											2023-07-25 15:28:30 +02:00
										 |  |  |     {"__weaklistoffset__", Py_T_PYSSIZET, offsetof(simplequeueobject, weakreflist), Py_READONLY}, | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  |     {NULL}, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyType_Slot simplequeue_slots[] = { | 
					
						
							|  |  |  |     {Py_tp_dealloc, simplequeue_dealloc}, | 
					
						
							|  |  |  |     {Py_tp_doc, (void *)simplequeue_new__doc__}, | 
					
						
							|  |  |  |     {Py_tp_traverse, simplequeue_traverse}, | 
					
						
							| 
									
										
										
										
											2021-05-27 17:50:12 +02:00
										 |  |  |     {Py_tp_clear, simplequeue_clear}, | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  |     {Py_tp_members, simplequeue_members}, | 
					
						
							|  |  |  |     {Py_tp_methods, simplequeue_methods}, | 
					
						
							|  |  |  |     {Py_tp_new, simplequeue_new}, | 
					
						
							|  |  |  |     {0, NULL}, | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  | static PyType_Spec simplequeue_spec = { | 
					
						
							|  |  |  |     .name = "_queue.SimpleQueue", | 
					
						
							|  |  |  |     .basicsize = sizeof(simplequeueobject), | 
					
						
							| 
									
										
										
										
											2021-06-17 12:06:09 +02:00
										 |  |  |     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | | 
					
						
							|  |  |  |               Py_TPFLAGS_IMMUTABLETYPE), | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  |     .slots = simplequeue_slots, | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Initialization function */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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."); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-19 09:24:37 +01:00
										 |  |  | 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}, | 
					
						
							| 
									
										
										
										
											2023-05-05 15:11:27 -06:00
										 |  |  |     {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, | 
					
						
							| 
									
										
										
										
											2024-05-03 08:30:55 -07:00
										 |  |  |     {Py_mod_gil, Py_MOD_GIL_NOT_USED}, | 
					
						
							| 
									
										
										
										
											2020-11-19 09:24:37 +01:00
										 |  |  |     {0, NULL} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | static struct PyModuleDef queuemodule = { | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  |     .m_base = PyModuleDef_HEAD_INIT, | 
					
						
							|  |  |  |     .m_name = "_queue", | 
					
						
							|  |  |  |     .m_doc = queue_module_doc, | 
					
						
							|  |  |  |     .m_size = sizeof(simplequeue_state), | 
					
						
							| 
									
										
										
										
											2020-11-19 09:24:37 +01:00
										 |  |  |     .m_slots = queuemodule_slots, | 
					
						
							| 
									
										
										
										
											2020-11-07 20:18:37 +01:00
										 |  |  |     .m_traverse = queue_traverse, | 
					
						
							|  |  |  |     .m_clear = queue_clear, | 
					
						
							|  |  |  |     .m_free = queue_free, | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyMODINIT_FUNC | 
					
						
							|  |  |  | PyInit__queue(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-11-19 09:24:37 +01:00
										 |  |  |    return PyModuleDef_Init(&queuemodule); | 
					
						
							| 
									
										
										
										
											2018-01-16 00:27:16 +01:00
										 |  |  | } |