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