1760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 2760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org#include "os/os_thread.h" 3760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org#include "pipe/p_defines.h" 4760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org#include "util/u_ringbuffer.h" 5760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org#include "util/u_math.h" 6760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org#include "util/u_memory.h" 7760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 8760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org/* Generic ringbuffer: 9760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org */ 10760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgstruct util_ringbuffer 11760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org{ 12760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org struct util_packet *buf; 13760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org unsigned mask; 14760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 15760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org /* Can this be done with atomic variables?? 16760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org */ 17760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org unsigned head; 18760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org unsigned tail; 19760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org pipe_condvar change; 20760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org pipe_mutex mutex; 21760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org}; 22760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 23760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 24760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgstruct util_ringbuffer *util_ringbuffer_create( unsigned dwords ) 25760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org{ 26760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org struct util_ringbuffer *ring = CALLOC_STRUCT(util_ringbuffer); 27760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if (ring == NULL) 28760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return NULL; 29760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 30760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org assert(util_is_power_of_two(dwords)); 31760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 32760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org ring->buf = MALLOC( dwords * sizeof(unsigned) ); 33760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if (ring->buf == NULL) 34760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org goto fail; 35760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 36760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org ring->mask = dwords - 1; 37760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 38760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org pipe_condvar_init(ring->change); 39760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org pipe_mutex_init(ring->mutex); 40760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return ring; 41760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 42760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgfail: 43760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org FREE(ring->buf); 44760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org FREE(ring); 45760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return NULL; 46760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org} 47760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 48760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgvoid util_ringbuffer_destroy( struct util_ringbuffer *ring ) 49760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org{ 50760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org pipe_condvar_destroy(ring->change); 51760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org pipe_mutex_destroy(ring->mutex); 52760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org FREE(ring->buf); 53760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org FREE(ring); 54760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org} 55760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 56760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org/** 57760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org * Return number of free entries in the ring 58760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org */ 59760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgstatic INLINE unsigned util_ringbuffer_space( const struct util_ringbuffer *ring ) 60760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org{ 61760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return (ring->tail - (ring->head + 1)) & ring->mask; 62760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org} 63760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 64760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org/** 65760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org * Is the ring buffer empty? 66760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org */ 67760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgstatic INLINE boolean util_ringbuffer_empty( const struct util_ringbuffer *ring ) 68760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org{ 69760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return util_ringbuffer_space(ring) == ring->mask; 70760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org} 71760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 72760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgvoid util_ringbuffer_enqueue( struct util_ringbuffer *ring, 73760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org const struct util_packet *packet ) 74760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org{ 75760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org unsigned i; 76760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 77760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org /* XXX: over-reliance on mutexes, etc: 78760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org */ 79760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org pipe_mutex_lock(ring->mutex); 80760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 81760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org /* make sure we don't request an impossible amount of space 82760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org */ 83760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org assert(packet->dwords <= ring->mask); 84760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 85760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org /* Wait for free space: 86760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org */ 87760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org while (util_ringbuffer_space(ring) < packet->dwords) 88760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org pipe_condvar_wait(ring->change, ring->mutex); 89760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 90760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org /* Copy data to ring: 91760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org */ 92760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for (i = 0; i < packet->dwords; i++) { 93760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 94760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org /* Copy all dwords of the packet. Note we're abusing the 95760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org * typesystem a little - we're being passed a pointer to 96760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org * something, but probably not an array of packet structs: 97760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org */ 98760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org ring->buf[ring->head] = packet[i]; 99760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org ring->head++; 100760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org ring->head &= ring->mask; 101760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org } 102760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 103760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org /* Signal change: 104760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org */ 105760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org pipe_condvar_signal(ring->change); 106760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org pipe_mutex_unlock(ring->mutex); 107760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org} 108760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 109760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgenum pipe_error util_ringbuffer_dequeue( struct util_ringbuffer *ring, 110760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org struct util_packet *packet, 111760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org unsigned max_dwords, 112760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org boolean wait ) 113760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org{ 114760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org const struct util_packet *ring_packet; 115760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org unsigned i; 116760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org int ret = PIPE_OK; 117760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 118760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org /* XXX: over-reliance on mutexes, etc: 119760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org */ 120760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org pipe_mutex_lock(ring->mutex); 121760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 122760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org /* Get next ring entry: 123760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org */ 124760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if (wait) { 125760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org while (util_ringbuffer_empty(ring)) 126760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org pipe_condvar_wait(ring->change, ring->mutex); 127760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org } 128760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org else { 129760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if (util_ringbuffer_empty(ring)) { 130760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org ret = PIPE_ERROR_OUT_OF_MEMORY; 131760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org goto out; 132760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org } 133760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org } 134760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 135760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org ring_packet = &ring->buf[ring->tail]; 136760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 137760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org /* Both of these are considered bugs. Raise an assert on debug builds. 138760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org */ 139760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if (ring_packet->dwords > ring->mask + 1 - util_ringbuffer_space(ring) || 140760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org ring_packet->dwords > max_dwords) { 141760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org assert(0); 142760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org ret = PIPE_ERROR_BAD_INPUT; 143760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org goto out; 144760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org } 145760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 146760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org /* Copy data from ring: 147760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org */ 148760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for (i = 0; i < ring_packet->dwords; i++) { 149760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org packet[i] = ring->buf[ring->tail]; 150760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org ring->tail++; 151760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org ring->tail &= ring->mask; 152760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org } 153760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 154760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgout: 155760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org /* Signal change: 156760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org */ 157760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org pipe_condvar_signal(ring->change); 158760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org pipe_mutex_unlock(ring->mutex); 159760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return ret; 160760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org} 161