PCQ(9) | Kernel Developer's Manual | PCQ(9) |
pcq
—
#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);
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.
pcq_create
(maxlen,
kmflags)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)pcq_get
(pcq)NULL
. The caller must
prevent concurrent gets from occurring.pcq_maxitems
(pcq)pcq_peek
(pcq)NULL
.pcq_put
(pcq,
item)false
; otherwise, return
true
. The item must not have the value of
NULL
.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.)
pcq
interface is implemented within the file
sys/kern/subr_pcq.c.
pcq
interface first appeared in
NetBSD 6.0.
January 22, 2012 | NetBSD 10.1 |