ringbuffer: use gcc atomic operations

Remove barrier, use GCC atomic operations for ringbuffer
This commit is contained in:
Wim Taymans 2017-04-24 13:18:57 +02:00
parent 02d4dc0efd
commit baada0a330
7 changed files with 32 additions and 92 deletions

View file

@ -189,9 +189,9 @@ loop_invoke (SpaLoop *loop,
res = func (loop, false, seq, size, data, user_data); res = func (loop, false, seq, size, data, user_data);
} else { } else {
int32_t filled, avail; int32_t filled, avail;
uint32_t offset, l0; uint32_t idx, offset, l0;
filled = spa_ringbuffer_get_write_index (&impl->buffer, &offset); filled = spa_ringbuffer_get_write_index (&impl->buffer, &idx);
if (filled < 0 || filled > impl->buffer.size) { if (filled < 0 || filled > impl->buffer.size) {
pinos_log_warn ("data-loop %p: queue xrun %d", impl, filled); pinos_log_warn ("data-loop %p: queue xrun %d", impl, filled);
return SPA_RESULT_ERROR; return SPA_RESULT_ERROR;
@ -201,7 +201,7 @@ loop_invoke (SpaLoop *loop,
pinos_log_warn ("data-loop %p: queue full %d", impl, avail); pinos_log_warn ("data-loop %p: queue full %d", impl, avail);
return SPA_RESULT_ERROR; return SPA_RESULT_ERROR;
} }
offset &= impl->buffer.mask; offset = idx & impl->buffer.mask;
l0 = offset + avail; l0 = offset + avail;
if (l0 > impl->buffer.size) if (l0 > impl->buffer.size)
@ -224,7 +224,7 @@ loop_invoke (SpaLoop *loop,
} }
memcpy (item->data, data, size); memcpy (item->data, data, size);
spa_ringbuffer_write_advance (&impl->buffer, item->item_size); spa_ringbuffer_write_update (&impl->buffer, idx + item->item_size);
pinos_loop_signal_event (&impl->this, impl->event); pinos_loop_signal_event (&impl->this, impl->event);
@ -242,12 +242,12 @@ event_func (SpaLoopUtils *utils,
void *data) void *data)
{ {
PinosLoopImpl *impl = data; PinosLoopImpl *impl = data;
uint32_t offset; uint32_t index;
while (spa_ringbuffer_get_read_index (&impl->buffer, &offset) > 0) { while (spa_ringbuffer_get_read_index (&impl->buffer, &index) > 0) {
InvokeItem *item = SPA_MEMBER (impl->buffer_data, offset & impl->buffer.mask, InvokeItem); InvokeItem *item = SPA_MEMBER (impl->buffer_data, index & impl->buffer.mask, InvokeItem);
item->func (impl->this.loop, true, item->seq, item->size, item->data, item->user_data); item->func (impl->this.loop, true, item->seq, item->size, item->data, item->user_data);
spa_ringbuffer_read_advance (&impl->buffer, item->item_size); spa_ringbuffer_read_update (&impl->buffer, index + item->item_size);
} }
} }

View file

@ -39,7 +39,7 @@ typedef struct {
size_t offset; size_t offset;
SpaEvent current; SpaEvent current;
uint32_t current_offset; uint32_t current_index;
} PinosTransportImpl; } PinosTransportImpl;
static size_t static size_t
@ -223,7 +223,7 @@ pinos_transport_add_event (PinosTransport *trans,
index & trans->output_buffer->mask, index & trans->output_buffer->mask,
event, event,
size); size);
spa_ringbuffer_write_advance (trans->output_buffer, size); spa_ringbuffer_write_update (trans->output_buffer, index + size);
return SPA_RESULT_OK; return SPA_RESULT_OK;
} }
@ -234,20 +234,17 @@ pinos_transport_next_event (PinosTransport *trans,
{ {
PinosTransportImpl *impl = (PinosTransportImpl *) trans; PinosTransportImpl *impl = (PinosTransportImpl *) trans;
int32_t avail; int32_t avail;
uint32_t index;
if (impl == NULL || event == NULL) if (impl == NULL || event == NULL)
return SPA_RESULT_INVALID_ARGUMENTS; return SPA_RESULT_INVALID_ARGUMENTS;
avail = spa_ringbuffer_get_read_index (trans->input_buffer, &index); avail = spa_ringbuffer_get_read_index (trans->input_buffer, &impl->current_index);
if (avail < sizeof (SpaEvent)) if (avail < sizeof (SpaEvent))
return SPA_RESULT_ENUM_END; return SPA_RESULT_ENUM_END;
impl->current_offset = index & trans->input_buffer->mask;
spa_ringbuffer_read_data (trans->input_buffer, spa_ringbuffer_read_data (trans->input_buffer,
trans->input_data, trans->input_data,
impl->current_offset, impl->current_index & trans->input_buffer->mask,
&impl->current, &impl->current,
sizeof (SpaEvent)); sizeof (SpaEvent));
@ -270,10 +267,10 @@ pinos_transport_parse_event (PinosTransport *trans,
spa_ringbuffer_read_data (trans->input_buffer, spa_ringbuffer_read_data (trans->input_buffer,
trans->input_data, trans->input_data,
impl->current_offset, impl->current_index & trans->input_buffer->mask,
event, event,
size); size);
spa_ringbuffer_read_advance (trans->input_buffer, size); spa_ringbuffer_read_update (trans->input_buffer, impl->current_index + size);
return SPA_RESULT_OK; return SPA_RESULT_OK;
} }

View file

@ -1,51 +0,0 @@
/* Simple Plugin API
* Copyright (C) 2016 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __SPA_BARRIER_H__
#define __SPA_BARRIER_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <spa/defs.h>
#if defined(__GNUC__)
# if defined( __i386__ ) || defined( __i486__ ) || defined( __i586__ ) || defined( __i686__ ) || defined( __x86_64__ )
# define spa_barrier_full() asm volatile("mfence":::"memory")
# define spa_barrier_read() asm volatile("lfence":::"memory")
# define spa_barrier_write() asm volatile("sfence":::"memory")
# elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
# define spa_barrier_full() __sync_synchronize()
# define spa_barrier_read() __sync_synchronize()
# define spa_barrier_write() __sync_synchronize()
# endif
#else
# warning no memory barriers support found
# define spa_barrier_full()
# define spa_barrier_read()
# define spa_barrier_write()
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __SPA_BARRIER_H__ */

View file

@ -1,6 +1,5 @@
spa_headers = [ spa_headers = [
'alloc-param.h', 'alloc-param.h',
'barrier.h',
'buffer.h', 'buffer.h',
'clock.h', 'clock.h',
'command.h', 'command.h',

View file

@ -32,7 +32,6 @@ typedef struct _SpaRingbuffer SpaRingbuffer;
#include <string.h> #include <string.h>
#include <spa/defs.h> #include <spa/defs.h>
#include <spa/barrier.h>
/** /**
* SpaRingbuffer: * SpaRingbuffer:
@ -103,9 +102,8 @@ spa_ringbuffer_get_read_index (SpaRingbuffer *rbuf,
{ {
int32_t avail; int32_t avail;
*index = rbuf->readindex; *index = __atomic_load_n (&rbuf->readindex, __ATOMIC_RELAXED);
avail = (int32_t) (rbuf->writeindex - *index); avail = (int32_t) (__atomic_load_n (&rbuf->writeindex, __ATOMIC_ACQUIRE) - *index);
spa_barrier_read();
return avail; return avail;
} }
@ -138,18 +136,17 @@ spa_ringbuffer_read_data (SpaRingbuffer *rbuf,
} }
/** /**
* spa_ringbuffer_read_advance: * spa_ringbuffer_read_update:
* @rbuf: a #SpaRingbuffer * @rbuf: a #SpaRingbuffer
* @len: number of bytes to advance * @index: new index
* *
* Advance the read pointer by @len * Update the read pointer to @index
*/ */
static inline void static inline void
spa_ringbuffer_read_advance (SpaRingbuffer *rbuf, spa_ringbuffer_read_update (SpaRingbuffer *rbuf,
int32_t len) int32_t index)
{ {
spa_barrier_full(); __atomic_store_n (&rbuf->readindex, index, __ATOMIC_RELEASE);
rbuf->readindex += len;
} }
/** /**
@ -169,9 +166,8 @@ spa_ringbuffer_get_write_index (SpaRingbuffer *rbuf,
{ {
int32_t filled; int32_t filled;
*index = rbuf->writeindex; *index = __atomic_load_n (&rbuf->writeindex, __ATOMIC_RELAXED);
filled = (int32_t) (*index - rbuf->readindex); filled = (int32_t) (*index - __atomic_load_n (&rbuf->readindex, __ATOMIC_ACQUIRE));
spa_barrier_full();
return filled; return filled;
} }
@ -193,19 +189,18 @@ spa_ringbuffer_write_data (SpaRingbuffer *rbuf,
} }
/** /**
* spa_ringbuffer_write_advance: * spa_ringbuffer_write_update:
* @rbuf: a #SpaRingbuffer * @rbuf: a #SpaRingbuffer
* @len: number of bytes to advance * @index: new index
* *
* Advance the write pointer by @len * Update the write pointer to @index
* *
*/ */
static inline void static inline void
spa_ringbuffer_write_advance (SpaRingbuffer *rbuf, spa_ringbuffer_write_update (SpaRingbuffer *rbuf,
int32_t len) int32_t index)
{ {
spa_barrier_write(); __atomic_store_n (&rbuf->writeindex, index, __ATOMIC_RELEASE);
rbuf->writeindex += len;
} }

View file

@ -372,7 +372,7 @@ pull_frames (SpaALSAState *state,
dst, dst,
n_bytes); n_bytes);
spa_ringbuffer_read_advance (ringbuffer, n_bytes); spa_ringbuffer_read_update (ringbuffer, index + n_bytes);
reuse = avail == n_bytes; reuse = avail == n_bytes;
} else { } else {
offs = SPA_MIN (d[0].chunk->offset + state->ready_offset, d[0].maxsize); offs = SPA_MIN (d[0].chunk->offset + state->ready_offset, d[0].maxsize);

View file

@ -324,7 +324,7 @@ audiotestsrc_make_buffer (SpaAudioTestSrc *this)
} else { } else {
this->render_func (this, SPA_MEMBER (b->outbuf->datas[0].data, offset, void), n_samples); this->render_func (this, SPA_MEMBER (b->outbuf->datas[0].data, offset, void), n_samples);
} }
spa_ringbuffer_write_advance (&b->rb->ringbuffer, n_bytes); spa_ringbuffer_write_update (&b->rb->ringbuffer, index + n_bytes);
} else { } else {
n_samples = n_bytes / this->bpf; n_samples = n_bytes / this->bpf;
this->render_func (this, b->outbuf->datas[0].data, n_samples); this->render_func (this, b->outbuf->datas[0].data, n_samples);