Created
April 12, 2025 14:21
-
-
Save skeeto/20756eb4c177744cb98354f5a6173097 to your computer and use it in GitHub Desktop.
Single consumer, single producer circular buffer using Win32 SRW
This file contains hidden or 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
// Single consumer, single producer circular buffer using Win32 SRW | |
// Ref: https://github.com/vibhav950/cbuf | |
// Ref: https://old.reddit.com/r/C_Programming/comments/1jwnlrf | |
// Ref: https://nullprogram.com/blog/2024/10/03/ | |
#include <stddef.h> | |
#include <stdint.h> | |
#include <string.h> | |
typedef uint8_t u8; | |
typedef int32_t b32; | |
typedef int32_t i32; | |
typedef ptrdiff_t iz; | |
typedef size_t uz; | |
typedef struct { uz _; } Lock; | |
typedef struct { uz _; } Cond; | |
#define W32(r) __declspec(dllimport) r __stdcall | |
W32(i32) SleepConditionVariableSRW(Cond *, Lock *, i32, i32); | |
W32(void) AcquireSRWLockExclusive(Lock *); | |
W32(void) ReleaseSRWLockExclusive(Lock *); | |
W32(void) WakeConditionVariable(Cond *); | |
typedef struct { | |
u8 *buf; | |
iz cap; | |
Lock m; | |
Cond cv; | |
u8 *writep; | |
u8 *readp; | |
} Queue; | |
static Queue queue_init(u8 *buf, iz cap) | |
{ | |
Queue q = {0}; | |
q.writep = q.readp = q.buf = buf; | |
q.cap = cap; | |
return q; | |
} | |
// Use -1 for timeout_ms to wait indefinitely. | |
static b32 queue_read(Queue *q, u8 *buf, iz len, i32 timeout_ms) | |
{ | |
AcquireSRWLockExclusive(&q->m); | |
iz avail = -1; | |
for (;;) { | |
avail = q->writep - q->readp; | |
avail += avail<0 ? q->cap : 0; | |
if (avail >= len) { | |
break; | |
} | |
if (!SleepConditionVariableSRW(&q->cv, &q->m, timeout_ms, 0)) { | |
ReleaseSRWLockExclusive(&q->m); | |
return 0; | |
} | |
// FIXME: get sleep time and reduce timeout_ms | |
} | |
iz trunc = q->cap - (q->readp - q->buf); | |
if (trunc < len) { | |
memcpy(buf, q->readp, (uz)trunc); | |
q->readp = q->buf; | |
buf += trunc; | |
len -= trunc; | |
} | |
memcpy(buf, q->readp, (uz)len); | |
q->readp += len; | |
ReleaseSRWLockExclusive(&q->m); | |
WakeConditionVariable(&q->cv); | |
return 1; | |
} | |
// Use -1 for timeout_ms to wait indefinitely. | |
static b32 queue_write(Queue *q, u8 *buf, iz len, i32 timeout_ms) | |
{ | |
AcquireSRWLockExclusive(&q->m); | |
iz avail = -1; | |
for (;;) { | |
avail = q->readp - q->writep; | |
avail += avail<=0 ? q->cap : 0; | |
if (avail >= len) { | |
break; | |
} | |
if (!SleepConditionVariableSRW(&q->cv, &q->m, timeout_ms, 0)) { | |
ReleaseSRWLockExclusive(&q->m); | |
return 0; | |
} | |
// FIXME: get sleep time and reduce timeout_ms | |
} | |
iz trunc = q->cap - (q->writep - q->buf); | |
if (trunc < len) { | |
memcpy(q->writep, buf, (uz)trunc); | |
q->writep = q->buf; | |
buf += trunc; | |
len -= trunc; | |
} | |
memcpy(q->writep, buf, (uz)len); | |
q->writep += len; | |
ReleaseSRWLockExclusive(&q->m); | |
WakeConditionVariable(&q->cv); | |
return 1; | |
} | |
// test / demo | |
#include <stdio.h> | |
#define lenof(a) ((i32)(sizeof(a) / sizeof(*(a)))) | |
int main(void) | |
{ | |
enum { cap = 8 }; | |
Queue q = queue_init((u8[cap]){0}, cap); | |
b32 ok = 0; | |
{ | |
u8 msg[] = "hello"; | |
ok = queue_write(&q, msg, lenof(msg)-1, 100); | |
printf("ok = %d\n", ok); | |
ok = queue_write(&q, msg, lenof(msg)-1, 100); | |
printf("ok = %d\n", ok); | |
} | |
{ | |
u8 buf[2] = {0}; | |
ok = queue_read(&q, buf, lenof(buf), 100); | |
printf("ok = %d [%.*s]\n", ok, lenof(buf), buf); | |
ok = queue_read(&q, buf, 2, 100); | |
printf("ok = %d [%.*s]\n", ok, lenof(buf), buf); | |
ok = queue_read(&q, buf, 2, 100); | |
printf("ok = %d [%.*s]\n", ok, lenof(buf), buf); | |
} | |
{ | |
u8 msg[] = "world"; | |
ok = queue_write(&q, msg, lenof(msg)-1, 100); | |
printf("ok = %d\n", ok); | |
} | |
{ | |
u8 buf[6] = {0}; | |
ok = queue_read(&q, buf, lenof(buf), 100); | |
printf("ok = %d [%.*s]\n", ok, lenof(buf), buf); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment