-
Notifications
You must be signed in to change notification settings - Fork 0
/
easy_ringbuf.h
125 lines (105 loc) · 3.32 KB
/
easy_ringbuf.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#ifndef __EASY_RINGBUF_H__
#define __EASY_RINGBUF_H__
typedef struct _EasyRingBufShared {
EASY_U32 read;
EASY_U32 write;
EASY_U32 pad0;
EASY_U32 pad1;
} EasyRingBufShared;
#define EASY_RINGBUF_MEM_OFFSET 16
typedef struct _EasyRingBuf {
EasyRingBufShared *head;
char *mem;
unsigned size;
} EasyRingBuf;
static inline void EasyRingBufInit(EasyRingBuf *ring, void *shared, unsigned size) {
ring->head = (EasyRingBufShared *)shared;
ring->mem = (char *)shared + EASY_RINGBUF_MEM_OFFSET;
ring->size = size - EASY_RINGBUF_MEM_OFFSET;
}
static inline int EasyRingBufCanRead(EasyRingBuf *ring) {
EASY_U32 write = EASY_ATOMIC_LOAD_ACQUIRE(ring->head->write);
EASY_U32 read = ring->head->read;
return read == write ? 0 : 1;
}
static inline int EasyRingBufCanWrite(EasyRingBuf *ring) {
EASY_U32 read = EASY_ATOMIC_LOAD_ACQUIRE(ring->head->read);
EASY_U32 write = ring->head->write;
if (write == read - 1) {
return 0;
}
if (read == 0 && write == ring->size - 1) {
return 0;
}
return 1;
}
static inline unsigned EasyRingBufRead(EasyRingBuf *ring, void *buf, unsigned size) {
unsigned readed, remaining, pos;
char *ptr = (char *)buf;
EASY_U32 write = EASY_ATOMIC_LOAD_ACQUIRE(ring->head->write);
EASY_U32 read = ring->head->read;
if (read == write) {
readed = 0;
} else if (read < write) {
readed = write - read;
if (readed > size) readed = size;
EASY_MEMCPY(ptr, ring->mem + read, readed);
EASY_ATOMIC_STORE_RELEASE(ring->head->read, read + readed);
} else {
readed = ring->size - read;
if (readed >= size) {
readed = size;
EASY_MEMCPY(ptr, ring->mem + read, readed);
pos = read + readed;
EASY_ATOMIC_STORE_RELEASE(ring->head->read, pos == ring->size ? 0 : pos);
} else {
EASY_MEMCPY(ptr, ring->mem + read, readed);
remaining = size - readed;
if (remaining > write) remaining = write;
if (remaining > 0) {
EASY_MEMCPY(ptr + readed, ring->mem, remaining);
readed += remaining;
}
EASY_ATOMIC_STORE_RELEASE(ring->head->read, remaining);
}
}
return readed;
}
static inline unsigned EasyRingBufWrite(EasyRingBuf *ring, void *buf, unsigned size) {
unsigned wrote, remaining, pos;
char *ptr = (char *)buf;
EASY_U32 read = EASY_ATOMIC_LOAD_ACQUIRE(ring->head->read);
EASY_U32 write = ring->head->write;
if (write < read) {
wrote = (read - 1) - write;
if (wrote > size) wrote = size;
if (wrote > 0) {
EASY_MEMCPY(ring->mem + write, ptr, wrote);
EASY_ATOMIC_STORE_RELEASE(ring->head->write, ring->head->write + wrote);
}
} else {
wrote = ring->size - write;
if (read == 0) wrote--;
if (wrote >= size) {
wrote = size;
EASY_MEMCPY(ring->mem + write, ptr, wrote);
pos = write + wrote;
EASY_ATOMIC_STORE_RELEASE(ring->head->write, pos == ring->size ? 0 : pos);
} else {
if (wrote > 0) EASY_MEMCPY(ring->mem + write, ptr, wrote);
if (read > 0) {
remaining = size - wrote;
if (remaining > read - 1) remaining = read - 1;
if (remaining > 0) {
EASY_MEMCPY(ring->mem, ptr + wrote, remaining);
wrote += remaining;
}
} else {
remaining = wrote + write;
}
EASY_ATOMIC_STORE_RELEASE(ring->head->write, remaining);
}
}
return wrote;
}
#endif // __EASY_RINGBUF_H__