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