Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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. }
  161.