Updated: 2022/Sep/29
Please read Privacy Policy. It's for your privacy.
PCQ(9) Kernel Developer's Manual PCQ(9) NAME pcq - producer/consumer queue SYNOPSIS #include <sys/pcq.h> pcq_t * pcq_create(size_t maxlen, km_flags_t kmflags); void pcq_destroy(pcq_t *pcq); void * pcq_get(pcq_t *pcq); size_t pcq_maxitems(pcq_t *pcq); void * pcq_peek(pcq_t *pcq); bool pcq_put(pcq_t *pcq, void *item); DESCRIPTION The machine-independent pcq interface provides lockless producer/consumer queues. A queue (pcq_t) allows multiple writers (producers), but only a single reader (consumer). The consumer is expected to be protected by a lock that covers the structure that the pcq_t is embedded into (e.g., socket lock, ifnet hwlock). These queues operate in a first-in, first- out (FIFO) manner. The act of inserting or removing an item from a pcq_t does not modify the item in any way. pcq does not prevent an item from being inserted multiple times into a single pcq_t. FUNCTIONS pcq_create(maxlen, kmflags) Create a queue that can store at most maxlen items at one time. kmflags should be either KM_SLEEP, if pcq_create() is allowed to sleep until resources are available, or KM_NOSLEEP if it should return NULL immediately, if resources are unavailable. pcq_destroy(pcq) Free the resources held by pcq. pcq_get(pcq) Remove the next item to be consumed from the queue and return it. If the queue is empty, return NULL. The caller must prevent concurrent gets from occurring. pcq_maxitems(pcq) Return the maximum number of items that the queue can store at any one time. pcq_peek(pcq) Return the next item to be consumed from the queue but do not remove it from the queue. If the queue is empty, return NULL. pcq_put(pcq, item) Place an item at the end of the queue. If there is no room in the queue for the item, return false; otherwise, return true. The item must not have the value of NULL. Memory ordering Any memory operations sequenced before pcq_put() of an item in one thread happen before all memory operations with data dependencies on the item returned by pcq_get() or pcq_peek() in another thread. For example: int mumble; /* producer */ mumble = 42; // A foo->x = 123; // B refcnt = foo->refcnt; // C pcq_put(pcq, foo); KASSERT(refcnt == 0); /* consumer */ foo = pcq_get(pcq); if (foo == NULL) return; atomic_inc_uint(&foo->refcnt); // D x = foo->x; // E if (x == 123) KASSERT(mumble == 42); // F In this example, memory operations B and C happen-before D and E. However, no ordering is guaranteed for A or F relative to any other memory operations, because the memory location of mumble is independent of the pointer foo returned by pcq_get(). If you must guarantee A happens before F, then on the consumer side, after pcq_get() or pcq_peek(), you can call membar_acquire() to turn it into an acquire operation instead of a consume operation; pcq_put() serves as the matching release operation. (This is a little dicey. Perhaps there should be separate pcq_peek_acq() and pcq_get_acq() operations if this semantics is necessary.) CODE REFERENCES The pcq interface is implemented within the file sys/kern/subr_pcq.c. SEE ALSO atomic_ops(3), queue(3) HISTORY The pcq interface first appeared in NetBSD 6.0. NetBSD 10.99 January 22, 2012 NetBSD 10.99