Merge branch '7.8'
[mesa.git] / src / gallium / auxiliary / util / u_ringbuffer.c
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
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
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 */
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 */
67 static INLINE boolean util_ringbuffer_empty( const struct util_ringbuffer *ring )
68 {
69 return util_ringbuffer_space(ring) == ring->mask;
70 }
71
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
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 }