Last active
November 27, 2015 16:28
-
-
Save BeRo1985/d00d4267684ed976d4d6 to your computer and use it in GitHub Desktop.
Lock Free Single Producer Single Consumer Ring Buffer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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