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 cnd_t change; 20 mtx_t 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) 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 cnd_init(&ring->change); 39 (void) mtx_init(&ring->mutex, mtx_plain); 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 cnd_destroy(&ring->change); 51 mtx_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 mtx_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 cnd_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 cnd_signal(&ring->change); 106 mtx_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 mtx_lock(&ring->mutex); 121 122 /* Get next ring entry: 123 */ 124 if (wait) { 125 while (util_ringbuffer_empty(ring)) 126 cnd_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 cnd_signal(&ring->change); 158 mtx_unlock(&ring->mutex); 159 return ret; 160 } 161