summaryrefslogtreecommitdiffstats
path: root/lf_ring_buffer.c
diff options
context:
space:
mode:
authorJérémy Zurcher <jeremy@asynk.ch>2010-01-10 13:47:14 +0100
committerJérémy Zurcher <jeremy@asynk.ch>2010-01-10 13:47:14 +0100
commitbb68ccdcc1dab0491edeb89c1382e95ebd16bf7a (patch)
treeb206fd7db252bb09d813a13a2f39f2254226c18d /lf_ring_buffer.c
parentea369cd15ee0a54a503852111cbd58fab19d9c2b (diff)
downloadlock_free-bb68ccdcc1dab0491edeb89c1382e95ebd16bf7a.zip
lock_free-bb68ccdcc1dab0491edeb89c1382e95ebd16bf7a.tar.gz
ring buffer : copy internal value first
Diffstat (limited to 'lf_ring_buffer.c')
-rw-r--r--lf_ring_buffer.c40
1 files changed, 21 insertions, 19 deletions
diff --git a/lf_ring_buffer.c b/lf_ring_buffer.c
index 70074bc..606e29a 100644
--- a/lf_ring_buffer.c
+++ b/lf_ring_buffer.c
@@ -83,25 +83,26 @@ int lf_ring_buffer_empty( lf_ring_buffer_t *r ) { return r->read_from==-1; }
/* write data into the ring buffer */
int lf_ring_buffer_write( lf_ring_buffer_t *r, void *data, int flags ) {
- int idx, next;
+ int write_to, read_from, next;
struct timespec backoff;
int backoff_time = BACKOFF_NANO_SLEEP;
/* reserve a buffer */
for(;;){
- idx = r->write_to;
- if(LFRB_IS_AVAILABLE( r->buffer[idx] ) ) {
- /* read_from==idx means that the buffer is full and that a writer thread which at first reserved this buffer
+ write_to = r->write_to;
+ read_from = r->read_from;
+ if(LFRB_IS_AVAILABLE( r->buffer[write_to] ) ) {
+ /* read_from==write_to means that the buffer is full and that a writer thread which at first reserved this buffer
* hasn't had enough CPU cycles to call MARK_AS_FILLED
*/
- if( r->read_from!=idx ) {
- next = idx+1;
+ if( read_from!=write_to ) {
+ next = write_to+1;
if (next==r->n_buf) next=0;
/* what might have happend between IS_AVAILABLE and now :
* - a writter has reserved this buffer => write_to has moved => CAS fails
* - a reader has consumed a buffer => read_from has moved => we've got more space
*/
- _LOG_CAS_( "write: CAS %d %d %d\n", r->write_to, idx, next );
- if( CompareAndSwapInt( &r->write_to, idx, next ) ) {
+ _LOG_CAS_( "write: CAS %d %d %d\n", r->write_to, write_to, next );
+ if( CompareAndSwapInt( &r->write_to, write_to, next ) ) {
/* !!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!
* - if the ring is empty before this write operation (r->read_from==-1 or latest idx)
* - and n_buf other threads execute this same function before the next CAS is finished
@@ -110,7 +111,7 @@ int lf_ring_buffer_write( lf_ring_buffer_t *r, void *data, int flags ) {
* - and see the ring as empty instead of full !!!!!
* so it will ends with two threads writing on this buffer
*/
- if(r->read_from==-1) CompareAndSwapInt( &r->read_from, -1, idx );
+ if(r->read_from==-1) CompareAndSwapInt( &r->read_from, -1, write_to );
break;
}
} else {
@@ -130,25 +131,26 @@ int lf_ring_buffer_write( lf_ring_buffer_t *r, void *data, int flags ) {
backoff_time += BACKOFF_NANO_SLEEP;
}
/* fill this buffer and mark it as filled */
- memcpy( LFRB_DATA_PTR(r->buffer[idx]), data, LFRB_DATA_SIZE );
- LFRB_MARK_AS_FILLED( r->buffer[idx] );
+ memcpy( LFRB_DATA_PTR(r->buffer[write_to]), data, LFRB_DATA_SIZE );
+ LFRB_MARK_AS_FILLED( r->buffer[write_to] );
return 0;
}
/* read data from the ring buffer */
int lf_ring_buffer_read( lf_ring_buffer_t *r, void *data, int flags ) {
- int idx, next;
+ int write_to, read_from, next;
struct timespec backoff;
int backoff_time = BACKOFF_NANO_SLEEP;
for(;;) {
- idx = r->read_from;
- if( !(LFRB_IS_AVAILABLE( r->buffer[idx] )) && r->read_from!=-1 ) {
- next = idx+1;
+ write_to = r->write_to;
+ read_from = r->read_from;
+ if( !(LFRB_IS_AVAILABLE( r->buffer[read_from] )) && read_from!=-1 ) {
+ next = read_from+1;
if (next==r->n_buf) next=0;
/* will do bad things if data dst buffer is too small !! */
- memcpy( data, LFRB_DATA_PTR(r->buffer[idx]), LFRB_DATA_SIZE );
- _LOG_CAS_( "read: CAS %d %d %d\n", r->read_from, idx, next );
- if( CompareAndSwapInt( &r->read_from, idx, next ) ) {
+ memcpy( data, LFRB_DATA_PTR(r->buffer[read_from]), LFRB_DATA_SIZE );
+ _LOG_CAS_( "read: CAS %d %d %d\n", r->read_from, read_from, next );
+ if( CompareAndSwapInt( &r->read_from, read_from, next ) ) {
if(r->read_from==r->write_to) {
/* the buffer is empty but writers will see it as full */
_LOG_CAS_( "read: empty CAS %d %d %d\n", r->read_from, next, -1 );
@@ -166,7 +168,7 @@ int lf_ring_buffer_read( lf_ring_buffer_t *r, void *data, int flags ) {
backoff_time += BACKOFF_NANO_SLEEP;
}
/* finish the read process */
- LFRB_MARK_AS_READ( r->buffer[idx] );
+ LFRB_MARK_AS_READ( r->buffer[read_from] );
return 0;
}