Skip to content

Instantly share code, notes, and snippets.

@BeRo1985
Last active November 27, 2015 16:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BeRo1985/d00d4267684ed976d4d6 to your computer and use it in GitHub Desktop.
Save BeRo1985/d00d4267684ed976d4d6 to your computer and use it in GitHub Desktop.
Lock Free Single Producer Single Consumer Ring Buffer
// Copyright (C) 2015 by Benjamin 'BeRo' Rosseaux
// licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication ( http://creativecommons.org/publicdomain/zero/1.0/ )
// Warning: Untested, written from scratch directly as a GitHubGist. It should only show the base idea behind it.
#define RingBufferInt int
#define RingBufferAtomicInt int
typedef int TRingBufferItem;
typedef TRingBufferItem *PRingBufferItem;
typedef struct {
RingBufferInt Size;
#ifndef WithOutFilled
RingBufferAtomicInt Filled;
#endif
RingBufferAtomicInt ReadPos;
RingBufferAtomicInt WritePos;
PRingBufferItem Data;
} TRingBuffer;
typedef TRingBuffer *PRingBuffer;
void RingBufferCreate(PRingBuffer RingBuffer, RingBufferInt Size){
memset(RingBuffer, 0, sizeof(TRingBuffer));
RingBuffer->Size = Size;
RingBuffer->Data = malloc(Size * sizeof(TRingBufferItem));
memset(RingBuffer->Data, 0, Size * sizeof(TRingBufferItem));
}
void RingBufferDestroy(PRingBuffer RingBuffer){
free(RingBuffer->Data);
memset(RingBuffer, 0, sizeof(TRingBuffer));
}
inline RingBufferInt RingBufferUsed(PRingBuffer RingBuffer){
#ifdef WithOutFilled
RingBufferInt LocalReadPos = atomic_load(&RingBuffer->ReadPos);
RingBufferInt LocalWritePos = atomic_load(&RingBuffer->WritePos);
return (LocalWritePos >= LocalReadPos) ? (LocalWritePos - LocalReadPos) : ((RingBuffer->Size - LocalReadPos) + LocalWritePos);
#else
return atomic_load(&RingBuffer->Filled);
#endif
}
inline RingBufferInt RingBufferFree(PRingBuffer RingBuffer){
#ifdef WithOutFilled
RingBufferAtomicInt LocalReadPos = atomic_load(&RingBuffer->ReadPos);
RingBufferAtomicInt LocalWritePos = atomic_load(&RingBuffer->WritePos);
return RingBuffer->Size - ((LocalWritePos >= LocalReadPos) ? (LocalWritePos - LocalReadPos) : ((RingBuffer->Size - LocalReadPos) + LocalWritePos));
#else
return RingBuffer->Size - atomic_load(&RingBuffer->Filled);
#endif
}
RingBufferInt RingBufferRead(PRingBuffer RingBuffer, PRingBufferItem Buffer, RingBufferInt Count){
RingBufferInt Size = RingBuffer->Size, Total, LocalReadPos = atomic_load(&RingBuffer->ReadPos), ToRead, Len;
#ifdef WithOutFilled
RingBufferInt LocalWritePos = atomic_load(&RingBuffer->WritePos);
Total = Size - ((LocalWritePos >= LocalReadPos) ? (LocalWritePos - LocalReadPos) : ((RingBuffer->Size - LocalReadPos) + LocalWritePos));
#else
Total = RingBuffer->Filled;
#endif
Len = Count;
if(Len > Total){
Len = Total
}else{
Total = Len;
}
while(Len > 0){
if((LocalReadPos + Len) > Size){
ToRead = Size - LocalReadPos;
memcpy(Buffer, &RingBuffer->Data[LocalReadPos], ToRead * sizeof(TRingBufferItem));
Buffer += ToRead;
Len -= ToRead;
LocalReadPos = 0;
}else{
memcpy(Buffer, &RingBuffer->Data[LocalReadPos], Len * sizeof(TRingBufferItem));
LocalReadPos += Len;
break;
}
}
while(LocalReadPos >= Size){
LocalReadPos -= Size;
}
atomic_store(&RingBuffer->ReadPos, LocalReadPos);
#ifndef WithOutFilled
atomic_fetch_sub(&RingBuffer->Filled, Bytes);
#endif
return Total;
}
RingBufferInt RingBufferWrite(PRingBuffer RingBuffer, PRingBufferItem Buffer, RingBufferInt Count){
RingBufferInt Size = RingBuffer->Size, Total, LocalWritePos, ToWrite, Len;
#ifdef WithOutFilled
RingBufferInt LocalReadPos = atomic_load(&RingBuffer->ReadPos);
LocalWritePos = atomic_load(&RingBuffer->WritePos);
Total = Size - ((LocalWritePos >= LocalReadPos) ? (LocalWritePos - LocalReadPos) : ((RingBuffer->Size - LocalReadPos) + LocalWritePos));
#else
Total = Size - RingBuffer->Filled;
#endif
Len = Count;
if(Total >= Len){
if(Len > Total){
Len = Total;
}
#ifndef WithOutFilled
LocalWritePos = atomic_load(&RingBuffer->WritePos);
#endif
while(Len > 0){
if((LocalWritePos + Len) > Size){
ToWrite = Size - LocalWritePos;
memcpy(&RingBuffer->Data[LocalWritePos], Buffer, ToWrite * sizeof(TRingBufferItem));
Buffer += ToWrite;
Len -= ToWrite;
LocalWritePos = 0;
}else{
memcpy(&RingBuffer->Data[LocalWritePos], Buffer, Len * sizeof(TRingBufferItem));
LocalWritePos += Len;
break;
}
}
while(LocalWritePos >= Size){
LocalWritePos -= Size;
}
atomic_store(&RingBuffer->WritePos, LocalWritePos);
#ifndef WithOutFilled
atomic_fetch_add(&RingBuffer->Filled, Bytes);
#endif
return Total;
}else{
return 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment