1 
2 #include "os/os_thread.h"
3 #include "pipe/p_defines.h"
4 #include "util/u_ringbuffer.h"
5 #include "util/u_math.h"
6 #include "util/u_memory.h"
7 
8 /* Generic ringbuffer:
9  */
10 struct util_ringbuffer
11 {
12    struct util_packet *buf;
13    unsigned mask;
14 
15    /* Can this be done with atomic variables??
16     */
17    unsigned head;
18    unsigned tail;
19    pipe_condvar change;
20    pipe_mutex mutex;
21 };
22 
23 
util_ringbuffer_create(unsigned dwords)24 struct util_ringbuffer *util_ringbuffer_create( unsigned dwords )
25 {
26    struct util_ringbuffer *ring = CALLOC_STRUCT(util_ringbuffer);
27    if (ring == NULL)
28       return NULL;
29 
30    assert(util_is_power_of_two(dwords));
31 
32    ring->buf = MALLOC( dwords * sizeof(unsigned) );
33    if (ring->buf == NULL)
34       goto fail;
35 
36    ring->mask = dwords - 1;
37 
38    pipe_condvar_init(ring->change);
39    pipe_mutex_init(ring->mutex);
40    return ring;
41 
42 fail:
43    FREE(ring->buf);
44    FREE(ring);
45    return NULL;
46 }
47 
util_ringbuffer_destroy(struct util_ringbuffer * ring)48 void util_ringbuffer_destroy( struct util_ringbuffer *ring )
49 {
50    pipe_condvar_destroy(ring->change);
51    pipe_mutex_destroy(ring->mutex);
52    FREE(ring->buf);
53    FREE(ring);
54 }
55 
56 /**
57  * Return number of free entries in the ring
58  */
util_ringbuffer_space(const struct util_ringbuffer * ring)59 static INLINE unsigned util_ringbuffer_space( const struct util_ringbuffer *ring )
60 {
61    return (ring->tail - (ring->head + 1)) & ring->mask;
62 }
63 
64 /**
65  * Is the ring buffer empty?
66  */
util_ringbuffer_empty(const struct util_ringbuffer * ring)67 static INLINE boolean util_ringbuffer_empty( const struct util_ringbuffer *ring )
68 {
69    return util_ringbuffer_space(ring) == ring->mask;
70 }
71 
util_ringbuffer_enqueue(struct util_ringbuffer * ring,const struct util_packet * packet)72 void util_ringbuffer_enqueue( struct util_ringbuffer *ring,
73                               const struct util_packet *packet )
74 {
75    unsigned i;
76 
77    /* XXX: over-reliance on mutexes, etc:
78     */
79    pipe_mutex_lock(ring->mutex);
80 
81    /* make sure we don't request an impossible amount of space
82     */
83    assert(packet->dwords <= ring->mask);
84 
85    /* Wait for free space:
86     */
87    while (util_ringbuffer_space(ring) < packet->dwords)
88       pipe_condvar_wait(ring->change, ring->mutex);
89 
90    /* Copy data to ring:
91     */
92    for (i = 0; i < packet->dwords; i++) {
93 
94       /* Copy all dwords of the packet.  Note we're abusing the
95        * typesystem a little - we're being passed a pointer to
96        * something, but probably not an array of packet structs:
97        */
98       ring->buf[ring->head] = packet[i];
99       ring->head++;
100       ring->head &= ring->mask;
101    }
102 
103    /* Signal change:
104     */
105    pipe_condvar_signal(ring->change);
106    pipe_mutex_unlock(ring->mutex);
107 }
108 
util_ringbuffer_dequeue(struct util_ringbuffer * ring,struct util_packet * packet,unsigned max_dwords,boolean wait)109 enum pipe_error util_ringbuffer_dequeue( struct util_ringbuffer *ring,
110                                          struct util_packet *packet,
111                                          unsigned max_dwords,
112                                          boolean wait )
113 {
114    const struct util_packet *ring_packet;
115    unsigned i;
116    int ret = PIPE_OK;
117 
118    /* XXX: over-reliance on mutexes, etc:
119     */
120    pipe_mutex_lock(ring->mutex);
121 
122    /* Get next ring entry:
123     */
124    if (wait) {
125       while (util_ringbuffer_empty(ring))
126          pipe_condvar_wait(ring->change, ring->mutex);
127    }
128    else {
129       if (util_ringbuffer_empty(ring)) {
130          ret = PIPE_ERROR_OUT_OF_MEMORY;
131          goto out;
132       }
133    }
134 
135    ring_packet = &ring->buf[ring->tail];
136 
137    /* Both of these are considered bugs.  Raise an assert on debug builds.
138     */
139    if (ring_packet->dwords > ring->mask + 1 - util_ringbuffer_space(ring) ||
140        ring_packet->dwords > max_dwords) {
141       assert(0);
142       ret = PIPE_ERROR_BAD_INPUT;
143       goto out;
144    }
145 
146    /* Copy data from ring:
147     */
148    for (i = 0; i < ring_packet->dwords; i++) {
149       packet[i] = ring->buf[ring->tail];
150       ring->tail++;
151       ring->tail &= ring->mask;
152    }
153 
154 out:
155    /* Signal change:
156     */
157    pipe_condvar_signal(ring->change);
158    pipe_mutex_unlock(ring->mutex);
159    return ret;
160 }
161