-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlfrb.c
More file actions
98 lines (86 loc) · 3.31 KB
/
Copy pathlfrb.c
File metadata and controls
98 lines (86 loc) · 3.31 KB
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
#include <stdatomic.h>
#include <stdbool.h>
#include <stdint.h>
#include "lfrb.h"
/**
* @brief LockFreeRingBufferの初期化
*
* @param rb 初期化対象のLockFreeRingBufferへのポインタ
*
* @return なし(void)
*/
void lfrb_init(LockFreeRingBuffer *rb) {
atomic_store_explicit(&rb->write_pos, 0, memory_order_relaxed);
atomic_store_explicit(&rb->read_pos, 0, memory_order_relaxed);
}
/**
* @brief 書き込み — Writerスレッド専用
*
* @param rb LockFreeRingBufferへのポインタ
* @param src 書き込むデータへのポインタ
* @param len 書き込むサンプル数
*
* @return true 書き込み成功、false バッファ溢れ
*
* @note
*
* [手順]
* 1. read_pos を acquire ロードして空き容量を確認
* 2. buf[] にデータを書き込む ← ここはアトミック不要
* 3. write_pos を release ストア ← buf書き込みの「完了宣言」
*
* release ストアにより、buf[]への書き込みが
* write_pos の更新より先に他スレッドから見えることが保証される。
*/
bool lfrb_write(LockFreeRingBuffer *rb, const int16_t *src, int len) {
int wp = atomic_load_explicit(&rb->write_pos, memory_order_relaxed);
int rp = atomic_load_explicit(&rb->read_pos, memory_order_acquire);
// 書き込み位置と読み出し位置の差がバッファサイズを超える場合は溢れとみなす
if (wp - rp + len > BUF_ELEM)
return false;
int wi = wp & BUF_MASK;
int tail = BUF_ELEM - wi;
if (tail >= len) {
memcpy(&rb->buf[wi], src, len * sizeof(int16_t));
} else {
memcpy(&rb->buf[wi], src, tail * sizeof(int16_t));
memcpy(&rb->buf[0], src + tail, (len - tail) * sizeof(int16_t));
}
atomic_store_explicit(&rb->write_pos, wp + len, memory_order_release);
return true;
}
/**
* @brief 読み出し — Readerスレッド専用
*
* @param rb LockFreeRingBufferへのポインタ
* @param dst 読み出すデータを格納するバッファへのポインタ
* @param len 読み出すサンプル数
* @param next_overlap 次回読み出し時のオーバーラップサンプル数(0以上len未満で指定)
*
* @return true 読み出し成功、false バッファ空
*
* @note
*
* [手順]
* 1. write_pos を acquire ロードしてデータ量を確認
* → これによりWriterの buf[] 書き込みが可視になることが保証される
* 2. buf[] からデータをコピー
* 3. read_pos を release ストア
*/
bool lfrb_read(LockFreeRingBuffer *rb, int16_t *dst, int len, int next_overlap) {
int rp = atomic_load_explicit(&rb->read_pos, memory_order_relaxed);
int wp = atomic_load_explicit(&rb->write_pos, memory_order_acquire);
// 書き込み位置と読み出し位置の差が必要なデータ量を満たさない場合は空とみなす
if (wp - rp < len)
return false;
int ri = rp & BUF_MASK;
int tail = BUF_ELEM - ri;
if (tail >= len) {
memcpy(dst, &rb->buf[ri], len * sizeof(int16_t));
} else {
memcpy(dst, &rb->buf[ri], tail * sizeof(int16_t));
memcpy(dst + tail, &rb->buf[0], (len - tail) * sizeof(int16_t));
}
atomic_store_explicit(&rb->read_pos, rp + len - next_overlap, memory_order_release);
return true;
}