1848b8605Smrg
2848b8605Smrg#include "os/os_thread.h"
3848b8605Smrg#include "pipe/p_defines.h"
4848b8605Smrg#include "util/u_ringbuffer.h"
5848b8605Smrg#include "util/u_math.h"
6848b8605Smrg#include "util/u_memory.h"
7848b8605Smrg
8848b8605Smrg/* Generic ringbuffer:
9848b8605Smrg */
10848b8605Smrgstruct util_ringbuffer
11848b8605Smrg{
12848b8605Smrg   struct util_packet *buf;
13848b8605Smrg   unsigned mask;
14848b8605Smrg
15848b8605Smrg   /* Can this be done with atomic variables??
16848b8605Smrg    */
17848b8605Smrg   unsigned head;
18848b8605Smrg   unsigned tail;
19b8e80941Smrg   cnd_t change;
20b8e80941Smrg   mtx_t mutex;
21848b8605Smrg};
22848b8605Smrg
23848b8605Smrg
24848b8605Smrgstruct util_ringbuffer *util_ringbuffer_create( unsigned dwords )
25848b8605Smrg{
26848b8605Smrg   struct util_ringbuffer *ring = CALLOC_STRUCT(util_ringbuffer);
27b8e80941Smrg   if (!ring)
28848b8605Smrg      return NULL;
29848b8605Smrg
30b8e80941Smrg   assert(util_is_power_of_two_or_zero(dwords));
31848b8605Smrg
32848b8605Smrg   ring->buf = MALLOC( dwords * sizeof(unsigned) );
33848b8605Smrg   if (ring->buf == NULL)
34848b8605Smrg      goto fail;
35848b8605Smrg
36848b8605Smrg   ring->mask = dwords - 1;
37848b8605Smrg
38b8e80941Smrg   cnd_init(&ring->change);
39b8e80941Smrg   (void) mtx_init(&ring->mutex, mtx_plain);
40848b8605Smrg   return ring;
41848b8605Smrg
42848b8605Smrgfail:
43848b8605Smrg   FREE(ring->buf);
44848b8605Smrg   FREE(ring);
45848b8605Smrg   return NULL;
46848b8605Smrg}
47848b8605Smrg
48848b8605Smrgvoid util_ringbuffer_destroy( struct util_ringbuffer *ring )
49848b8605Smrg{
50b8e80941Smrg   cnd_destroy(&ring->change);
51b8e80941Smrg   mtx_destroy(&ring->mutex);
52848b8605Smrg   FREE(ring->buf);
53848b8605Smrg   FREE(ring);
54848b8605Smrg}
55848b8605Smrg
56848b8605Smrg/**
57848b8605Smrg * Return number of free entries in the ring
58848b8605Smrg */
59b8e80941Smrgstatic inline unsigned util_ringbuffer_space( const struct util_ringbuffer *ring )
60848b8605Smrg{
61848b8605Smrg   return (ring->tail - (ring->head + 1)) & ring->mask;
62848b8605Smrg}
63848b8605Smrg
64848b8605Smrg/**
65848b8605Smrg * Is the ring buffer empty?
66848b8605Smrg */
67b8e80941Smrgstatic inline boolean util_ringbuffer_empty( const struct util_ringbuffer *ring )
68848b8605Smrg{
69848b8605Smrg   return util_ringbuffer_space(ring) == ring->mask;
70848b8605Smrg}
71848b8605Smrg
72848b8605Smrgvoid util_ringbuffer_enqueue( struct util_ringbuffer *ring,
73848b8605Smrg                              const struct util_packet *packet )
74848b8605Smrg{
75848b8605Smrg   unsigned i;
76848b8605Smrg
77848b8605Smrg   /* XXX: over-reliance on mutexes, etc:
78848b8605Smrg    */
79b8e80941Smrg   mtx_lock(&ring->mutex);
80848b8605Smrg
81848b8605Smrg   /* make sure we don't request an impossible amount of space
82848b8605Smrg    */
83848b8605Smrg   assert(packet->dwords <= ring->mask);
84848b8605Smrg
85848b8605Smrg   /* Wait for free space:
86848b8605Smrg    */
87848b8605Smrg   while (util_ringbuffer_space(ring) < packet->dwords)
88b8e80941Smrg      cnd_wait(&ring->change, &ring->mutex);
89848b8605Smrg
90848b8605Smrg   /* Copy data to ring:
91848b8605Smrg    */
92848b8605Smrg   for (i = 0; i < packet->dwords; i++) {
93848b8605Smrg
94848b8605Smrg      /* Copy all dwords of the packet.  Note we're abusing the
95848b8605Smrg       * typesystem a little - we're being passed a pointer to
96848b8605Smrg       * something, but probably not an array of packet structs:
97848b8605Smrg       */
98848b8605Smrg      ring->buf[ring->head] = packet[i];
99848b8605Smrg      ring->head++;
100848b8605Smrg      ring->head &= ring->mask;
101848b8605Smrg   }
102848b8605Smrg
103848b8605Smrg   /* Signal change:
104848b8605Smrg    */
105b8e80941Smrg   cnd_signal(&ring->change);
106b8e80941Smrg   mtx_unlock(&ring->mutex);
107848b8605Smrg}
108848b8605Smrg
109848b8605Smrgenum pipe_error util_ringbuffer_dequeue( struct util_ringbuffer *ring,
110848b8605Smrg                                         struct util_packet *packet,
111848b8605Smrg                                         unsigned max_dwords,
112848b8605Smrg                                         boolean wait )
113848b8605Smrg{
114848b8605Smrg   const struct util_packet *ring_packet;
115848b8605Smrg   unsigned i;
116848b8605Smrg   int ret = PIPE_OK;
117848b8605Smrg
118848b8605Smrg   /* XXX: over-reliance on mutexes, etc:
119848b8605Smrg    */
120b8e80941Smrg   mtx_lock(&ring->mutex);
121848b8605Smrg
122848b8605Smrg   /* Get next ring entry:
123848b8605Smrg    */
124848b8605Smrg   if (wait) {
125848b8605Smrg      while (util_ringbuffer_empty(ring))
126b8e80941Smrg         cnd_wait(&ring->change, &ring->mutex);
127848b8605Smrg   }
128848b8605Smrg   else {
129848b8605Smrg      if (util_ringbuffer_empty(ring)) {
130848b8605Smrg         ret = PIPE_ERROR_OUT_OF_MEMORY;
131848b8605Smrg         goto out;
132848b8605Smrg      }
133848b8605Smrg   }
134848b8605Smrg
135848b8605Smrg   ring_packet = &ring->buf[ring->tail];
136848b8605Smrg
137848b8605Smrg   /* Both of these are considered bugs.  Raise an assert on debug builds.
138848b8605Smrg    */
139848b8605Smrg   if (ring_packet->dwords > ring->mask + 1 - util_ringbuffer_space(ring) ||
140848b8605Smrg       ring_packet->dwords > max_dwords) {
141848b8605Smrg      assert(0);
142848b8605Smrg      ret = PIPE_ERROR_BAD_INPUT;
143848b8605Smrg      goto out;
144848b8605Smrg   }
145848b8605Smrg
146848b8605Smrg   /* Copy data from ring:
147848b8605Smrg    */
148848b8605Smrg   for (i = 0; i < ring_packet->dwords; i++) {
149848b8605Smrg      packet[i] = ring->buf[ring->tail];
150848b8605Smrg      ring->tail++;
151848b8605Smrg      ring->tail &= ring->mask;
152848b8605Smrg   }
153848b8605Smrg
154848b8605Smrgout:
155848b8605Smrg   /* Signal change:
156848b8605Smrg    */
157b8e80941Smrg   cnd_signal(&ring->change);
158b8e80941Smrg   mtx_unlock(&ring->mutex);
159848b8605Smrg   return ret;
160848b8605Smrg}
161