text: 
  #include "os/os_thread.h"
  #include "pipe/p_defines.h"
  #include "util/u_ringbuffer.h"
  #include "util/u_math.h"
  #include "util/u_memory.h"
  
  /* Generic ringbuffer: 
   */
  struct util_ringbuffer 
  {
     struct util_packet *buf;
     unsigned mask;
  
     /* Can this be done with atomic variables??
      */
     unsigned head;
     unsigned tail;
     cnd_t change;
     mtx_t mutex;
  };
  
  
  struct util_ringbuffer *util_ringbuffer_create( unsigned dwords )
  {
     struct util_ringbuffer *ring = CALLOC_STRUCT(util_ringbuffer);
     if (!ring)
        return NULL;
  
     assert(util_is_power_of_two_or_zero(dwords));
     
     ring->buf = MALLOC( dwords * sizeof(unsigned) );
     if (ring->buf == NULL)
        goto fail;
  
     ring->mask = dwords - 1;
  
     cnd_init(&ring->change);
     (void) mtx_init(&ring->mutex, mtx_plain);
     return ring;
  
  fail:
     FREE(ring->buf);
     FREE(ring);
     return NULL;
  }
  
  void util_ringbuffer_destroy( struct util_ringbuffer *ring )
  {
     cnd_destroy(&ring->change);
     mtx_destroy(&ring->mutex);
     FREE(ring->buf);
     FREE(ring);
  }
  
  /**
   * Return number of free entries in the ring
   */
  static inline unsigned util_ringbuffer_space( const struct util_ringbuffer *ring )
  {
     return (ring->tail - (ring->head + 1)) & ring->mask;
  }
  
  /**
   * Is the ring buffer empty?
   */
  static inline boolean util_ringbuffer_empty( const struct util_ringbuffer *ring )
  {
     return util_ringbuffer_space(ring) == ring->mask;
  }
  
  void util_ringbuffer_enqueue( struct util_ringbuffer *ring,
                                const struct util_packet *packet )
  {
     unsigned i;
  
     /* XXX: over-reliance on mutexes, etc:
      */
     mtx_lock(&ring->mutex);
  
     /* make sure we don't request an impossible amount of space
      */
     assert(packet->dwords <= ring->mask);
  
     /* Wait for free space:
      */
     while (util_ringbuffer_space(ring) < packet->dwords)
        cnd_wait(&ring->change, &ring->mutex);
  
     /* Copy data to ring:
      */
     for (i = 0; i < packet->dwords; i++) {
  
        /* Copy all dwords of the packet.  Note we're abusing the
         * typesystem a little - we're being passed a pointer to
         * something, but probably not an array of packet structs:
         */
        ring->buf[ring->head] = packet[i];
        ring->head++;
        ring->head &= ring->mask;
     }
  
     /* Signal change:
      */
     cnd_signal(&ring->change);
     mtx_unlock(&ring->mutex);
  }
  
  enum pipe_error util_ringbuffer_dequeue( struct util_ringbuffer *ring,
                                           struct util_packet *packet,
                                           unsigned max_dwords,
                                           boolean wait )
  {
     const struct util_packet *ring_packet;
     unsigned i;
     int ret = PIPE_OK;
  
     /* XXX: over-reliance on mutexes, etc:
      */
     mtx_lock(&ring->mutex);
  
     /* Get next ring entry:
      */
     if (wait) {
        while (util_ringbuffer_empty(ring))
           cnd_wait(&ring->change, &ring->mutex);
     }
     else {
        if (util_ringbuffer_empty(ring)) {
           ret = PIPE_ERROR_OUT_OF_MEMORY;
           goto out;
        }
     }
  
     ring_packet = &ring->buf[ring->tail];
  
     /* Both of these are considered bugs.  Raise an assert on debug builds.
      */
     if (ring_packet->dwords > ring->mask + 1 - util_ringbuffer_space(ring) ||
         ring_packet->dwords > max_dwords) {
        assert(0);
        ret = PIPE_ERROR_BAD_INPUT;
        goto out;
     }
  
     /* Copy data from ring:
      */
     for (i = 0; i < ring_packet->dwords; i++) {
        packet[i] = ring->buf[ring->tail];
        ring->tail++;
        ring->tail &= ring->mask;
     }
  
  out:
     /* Signal change:
      */
     cnd_signal(&ring->change);
     mtx_unlock(&ring->mutex);
     return ret;
  }
  