libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
write_port.cpp
1#include "write_port.hpp"
2
3#include <new>
4
5using namespace LibXR;
6
8template class LibXR::SPSCQueue<uint8_t>;
9
10WritePort::WritePort(size_t queue_size, size_t buffer_size)
11 : queue_info_(new (std::align_val_t(LibXR::CONCURRENCY_ALIGNMENT))
12 SPSCQueue<WriteInfoBlock>(queue_size)),
13 queue_data_(buffer_size > 0 ? new (std::align_val_t(LibXR::CONCURRENCY_ALIGNMENT))
14 SPSCQueue<uint8_t>(buffer_size)
15 : nullptr)
16{
17}
18
20{
21 ASSERT(queue_data_ != nullptr);
22 return queue_data_->EmptySize();
23}
24
26{
27 ASSERT(queue_data_ != nullptr);
28 return queue_data_->Size();
29}
30
31bool WritePort::Writable() { return write_fun_ != nullptr; }
32
34{
35 write_fun_ = fun;
36 return *this;
37}
38
39void WritePort::Finish(bool in_isr, ErrorCode ans, WriteInfoBlock& info)
40{
41 if (info.op.type == WriteOperation::OperationType::BLOCK)
42 {
43 block_result_ = ans;
44
45 // Write completion claims the active BLOCK waiter and hands the wakeup to it.
46 // 写完成 claim 当前 BLOCK waiter,并把唤醒交给它。
48 if (busy_.compare_exchange_strong(expected, BusyState::BLOCK_CLAIMED,
49 std::memory_order_acq_rel,
50 std::memory_order_acquire))
51 {
52 info.op.data.sem_info.sem->PostFromCallback(in_isr);
53 return;
54 }
55
56 // The waiter may have timed out and detached before this late completion is
57 // reported.
58 // waiter 可能已经先超时分离,随后迟到完成才上报。
59 if (expected == BusyState::BLOCK_PUBLISHING)
60 {
62 if (busy_.compare_exchange_strong(expected, BusyState::BLOCK_CLAIMED,
63 std::memory_order_acq_rel,
64 std::memory_order_acquire))
65 {
66 info.op.data.sem_info.sem->PostFromCallback(in_isr);
67 return;
68 }
69 }
70
71 ASSERT(expected == BusyState::BLOCK_DETACHED || expected == BusyState::IDLE ||
72 expected == BusyState::LOCKED || expected == BusyState::RESETTING);
73 if (expected == BusyState::BLOCK_DETACHED)
74 {
76 (void)busy_.compare_exchange_strong(expected, BusyState::IDLE,
77 std::memory_order_acq_rel,
78 std::memory_order_acquire);
79 }
80 return;
81 }
82
83 info.op.UpdateStatus(in_isr, ans);
84}
85
87
89{
90 if (Writable())
91 {
92 if (data.size_ == 0)
93 {
94 if (op.type != WriteOperation::OperationType::BLOCK)
95 {
96 op.UpdateStatus(in_isr, ErrorCode::OK);
97 }
98 return ErrorCode::OK;
99 }
100
101 BusyState expected = BusyState::IDLE;
102 if (!busy_.compare_exchange_strong(expected, BusyState::LOCKED,
103 std::memory_order_acq_rel,
104 std::memory_order_acquire))
105 {
106 return ErrorCode::BUSY;
107 }
108
109 return CommitWrite(data, op, false, in_isr);
110 }
111 else
112 {
114 }
115}
116
118 bool in_isr)
119{
120 if (!meta_pushed && queue_info_->EmptySize() < 1)
121 {
122 busy_.store(BusyState::IDLE, std::memory_order_release);
123 return ErrorCode::FULL;
124 }
125
127 if (!meta_pushed)
128 {
129 if (queue_data_->EmptySize() < data.size_)
130 {
131 busy_.store(BusyState::IDLE, std::memory_order_release);
132 return ErrorCode::FULL;
133 }
134
135 ans =
136 queue_data_->PushBatch(reinterpret_cast<const uint8_t*>(data.addr_), data.size_);
137 UNUSED(ans);
138 ASSERT(ans == ErrorCode::OK);
139
140 if (op.type == WriteOperation::OperationType::BLOCK)
141 {
142 // The BLOCK waiter must be armed before queue_info_ becomes visible to a
143 // backend/completion thread.
144 // queue_info_ 对后端/完成线程可见前,必须先挂起 BLOCK waiter。
145 op.MarkAsRunning();
146 busy_.store(BusyState::BLOCK_PUBLISHING, std::memory_order_release);
147 }
148
149 WriteInfoBlock info{data, op};
150 ans = queue_info_->Push(info);
151
152 ASSERT(ans == ErrorCode::OK);
153 }
154
155 // Non-BLOCK ops are armed here. BLOCK ops submitted through Stream::SubmitBuffered()
156 // were already armed (MarkAsRunning + BLOCK_PUBLISHING) before the metadata was
157 // published, so the meta_pushed re-arm below is an idempotent no-op kept only to cover
158 // the direct-submit (meta_pushed == false) BLOCK path, which arms via BLOCK_PUBLISHING
159 // above. MarkAsRunning only affects POLLING ops, so re-marking a BLOCK op is harmless.
160 // 非 BLOCK op 在此挂起。经 Stream::SubmitBuffered() 提交的 BLOCK op 在发布元数据前
161 // 已经挂起(MarkAsRunning + BLOCK_PUBLISHING),因此下面 meta_pushed 分支的重复挂起
162 // 是幂等空操作,仅为覆盖直接提交(meta_pushed == false)的 BLOCK 路径而保留。
163 // MarkAsRunning 只对 POLLING op 生效,重复标记 BLOCK op 无副作用。
164 if (op.type != WriteOperation::OperationType::BLOCK)
165 {
166 op.MarkAsRunning();
167 }
168 else if (meta_pushed)
169 {
170 op.MarkAsRunning();
171 }
172
173 if (op.type == WriteOperation::OperationType::BLOCK)
174 {
176 if (!busy_.compare_exchange_strong(expected, BusyState::BLOCK_WAITING,
177 std::memory_order_acq_rel,
178 std::memory_order_acquire))
179 {
180 ASSERT(expected == BusyState::BLOCK_CLAIMED);
181 }
182 }
183
184 ans = write_fun_(*this, in_isr);
185
186 if (ans != ErrorCode::PENDING)
187 {
188 if (op.type == WriteOperation::OperationType::BLOCK)
189 {
190 auto state = busy_.load(std::memory_order_acquire);
191 while (state == BusyState::RESETTING)
192 {
193 state = busy_.load(std::memory_order_acquire);
194 }
195
196 if (state == BusyState::BLOCK_CLAIMED)
197 {
198 auto finish_wait_ans = op.data.sem_info.sem->Wait(UINT32_MAX);
199 UNUSED(finish_wait_ans);
200 ASSERT(finish_wait_ans == ErrorCode::OK);
201 busy_.store(BusyState::IDLE, std::memory_order_release);
202 return block_result_;
203 }
204
205 if (state == BusyState::BLOCK_DETACHED)
206 {
207 busy_.store(BusyState::IDLE, std::memory_order_release);
208 return ErrorCode::TIMEOUT;
209 }
210
211 ASSERT(state == BusyState::BLOCK_WAITING || state == BusyState::IDLE ||
212 state == BusyState::LOCKED);
213 busy_.store(BusyState::IDLE, std::memory_order_release);
214 return ans;
215 }
216
217 if (!meta_pushed)
218 {
219 busy_.store(BusyState::IDLE, std::memory_order_release);
220 }
221
222 if (op.type != WriteOperation::OperationType::BLOCK)
223 {
224 op.UpdateStatus(in_isr, ans);
225 }
226 return (static_cast<int8_t>(ans) < 0) ? ans : ErrorCode::OK;
227 }
228
229 if (op.type == WriteOperation::OperationType::BLOCK)
230 {
231 ASSERT(!in_isr);
232 auto wait_ans = op.data.sem_info.sem->Wait(op.data.sem_info.timeout);
233 if (wait_ans == ErrorCode::OK)
234 {
235 // BLOCK_CLAIMED is always released by the waiter itself.
236 // BLOCK_CLAIMED 始终由 waiter 自己释放。
237#ifdef LIBXR_DEBUG_BUILD
238 auto state = busy_.load(std::memory_order_acquire);
239 ASSERT(state == BusyState::BLOCK_CLAIMED);
240#endif
241 busy_.store(BusyState::IDLE, std::memory_order_release);
242 return block_result_;
243 }
244
245 // Timeout won before completion claimed the waiter.
246 // 超时先赢,完成侧还没 claim 当前 waiter。
248 if (busy_.compare_exchange_strong(expected, BusyState::BLOCK_DETACHED,
249 std::memory_order_acq_rel,
250 std::memory_order_acquire))
251 {
252 return ErrorCode::TIMEOUT;
253 }
254
255 if (expected != BusyState::BLOCK_CLAIMED)
256 {
257 while (expected == BusyState::RESETTING)
258 {
259 expected = busy_.load(std::memory_order_acquire);
260 }
261
262 // A detached late completion may already have cleared BLOCK_DETACHED
263 // back to IDLE before this waiter wakes from timeout.
264 // 分离后的迟到完成可能会在当前 waiter 超时醒来前,先把
265 // BLOCK_DETACHED 清回 IDLE。
266 ASSERT(expected == BusyState::BLOCK_DETACHED || expected == BusyState::IDLE ||
267 expected == BusyState::LOCKED);
268 if (expected == BusyState::BLOCK_DETACHED)
269 {
270 busy_.store(BusyState::IDLE, std::memory_order_release);
271 }
272 return ErrorCode::TIMEOUT;
273 }
274
275 // Timeout lost after completion had already claimed the waiter.
276 // 超时发生得太晚,完成侧已经 claim 了当前 waiter。
277 auto finish_wait_ans = op.data.sem_info.sem->Wait(UINT32_MAX);
278 UNUSED(finish_wait_ans);
279 ASSERT(finish_wait_ans == ErrorCode::OK);
280 busy_.store(BusyState::IDLE, std::memory_order_release);
281
282 return block_result_;
283 }
284
285 if (!meta_pushed)
286 {
287 busy_.store(BusyState::IDLE, std::memory_order_release);
288 }
289
290 return ErrorCode::OK;
291}
292
293void WritePort::FailAndClearAll(ErrorCode reason, bool in_isr)
294{
295 ASSERT(queue_data_ != nullptr);
296 WriteInfoBlock info{};
297
298 while (true)
299 {
300 auto state = busy_.load(std::memory_order_acquire);
301
302 if (state == BusyState::LOCKED)
303 {
304 DEV_ASSERT_FROM_CALLBACK(false, in_isr);
305 return;
306 }
307
308 if (state == BusyState::BLOCK_PUBLISHING)
309 {
310 DEV_ASSERT_FROM_CALLBACK(false, in_isr);
311 return;
312 }
313
314 if (state == BusyState::RESETTING)
315 {
316 DEV_ASSERT_FROM_CALLBACK(false, in_isr);
317 return;
318 }
319
320 if (state == BusyState::IDLE)
321 {
322 BusyState expected = BusyState::IDLE;
323 if (!busy_.compare_exchange_strong(expected, BusyState::RESETTING,
324 std::memory_order_acq_rel,
325 std::memory_order_acquire))
326 {
327 continue;
328 }
329
331 while (queue_info_->Pop(info) == ErrorCode::OK)
332 {
333 Finish(in_isr, reason, info);
334 }
336 busy_.store(BusyState::IDLE, std::memory_order_release);
337 return;
338 }
339
340 if (state == BusyState::BLOCK_WAITING)
341 {
342 // Keep BLOCK_WAITING visible until Finish() hands the terminal wakeup to
343 // the blocked caller. Switching to RESETTING here would break that
344 // existing waiter handoff.
345 // 这里必须保留 BLOCK_WAITING,直到 Finish() 把最终唤醒交给当前
346 // BLOCK waiter;若先切成 RESETTING,会破坏既有 waiter 交接。
348 while (queue_info_->Pop(info) == ErrorCode::OK)
349 {
350 Finish(in_isr, reason, info);
351 }
352 return;
353 }
354
355 if (state == BusyState::BLOCK_DETACHED)
356 {
357 // The waiter is already gone, but BLOCK_DETACHED still blocks reentrant
358 // submissions while old queue entries are drained.
359 // waiter 已经离开,但 BLOCK_DETACHED 仍能在清理旧队列期间挡住重入提交。
361 while (queue_info_->Pop(info) == ErrorCode::OK)
362 {
363 // The waiter has already detached. Finish() will clear the local state
364 // without re-posting that waiter.
365 // waiter 已经分离。Finish() 会清理本地状态,但不会重新唤醒该 waiter。
366 Finish(in_isr, reason, info);
367 }
369 busy_.store(BusyState::IDLE, std::memory_order_release);
370 return;
371 }
372
373 if (state == BusyState::BLOCK_CLAIMED)
374 {
375 return;
376 }
377 }
378}
只读原始数据视图 / Immutable raw data view
size_t size_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address
union LibXR::Operation::@5 data
void UpdateStatus(bool in_isr, Status &&status)
Updates operation status based on type.
void MarkAsRunning()
标记操作为运行状态。 Marks the operation as running.
OperationType type
size_t Size() const
获取当前已用元素数 / Get the current element count
size_t EmptySize() const
获取剩余空槽数 / Get the current free-slot count
单生产者单消费者无锁队列。
void Reset()
重置队列状态。
ErrorCode PushBatch(const Data *data, size_t size)
批量推入多个 payload。
void PostFromCallback(bool in_isr)
从中断回调中释放(增加)信号量 Releases (increments) the semaphore from an ISR (Interrupt Service Routine)
Definition semaphore.cpp:99
ErrorCode Wait(uint32_t timeout=UINT32_MAX)
等待(减少)信号量 Waits (decrements) the semaphore
Definition semaphore.cpp:52
WritePort class for handling write operations.
size_t EmptySize()
获取数据队列的剩余可用空间。 Gets the remaining available space in the data queue.
void FailAndClearAll(ErrorCode reason, bool in_isr)
失败完成并清空当前所有挂起写操作。
size_t Size()
获取当前数据队列的已使用大小。 Gets the used size of the current data queue.
void Finish(bool in_isr, ErrorCode ans, WriteInfoBlock &info)
更新写入操作的状态。 Updates the status of the write operation.
ErrorCode block_result_
SPSCQueue< WriteInfoBlock > * queue_info_
Metadata queue for pending write batches. 挂起写批次的元数据队列。
WritePort(size_t queue_size=3, size_t buffer_size=128)
构造一个新的 WritePort 对象。 Constructs a new WritePort object.
WritePort & operator=(WriteFun fun)
赋值运算符重载,用于设置写入函数。 Overloaded assignment operator to set the write function.
std::atomic< BusyState > busy_
Shared submit/wait handoff state. 共享的提交/等待交接状态。
@ BLOCK_CLAIMED
Final wakeup belongs to the current waiter. 最终唤醒已归当前等待者所有。
@ LOCKED
Submission path owns queue mutation. 提交路径占有写队列/元数据修改权。
SPSCQueue< uint8_t > * queue_data_
Payload queue for pending write bytes. 挂起写入字节的数据队列。
bool Writable()
判断端口是否可写。 Checks whether the port is writable.
WriteFun write_fun_
Driver/backend write entry. 底层驱动或后端写入入口。
ErrorCode CommitWrite(ConstRawData data, WriteOperation &op, bool pushed=false, bool in_isr=false)
提交写入操作。 Commits a write operation.
void MarkAsRunning(WriteOperation &op)
标记写入操作为运行中。 Marks the write operation as running.
ErrorCode operator()(ConstRawData data, WriteOperation &op, bool in_isr=false)
执行写入操作。 Performs a write operation.
LibXR 命名空间
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举
@ TIMEOUT
超时 | Timeout
@ BUSY
忙碌 | Busy
@ NOT_SUPPORT
不支持 | Not supported
@ FULL
已满 | Full
@ PENDING
等待中 | Pending
@ OK
操作成功 | Operation successful
ErrorCode(* WriteFun)(WritePort &port, bool in_isr)
Function pointer type for write operations.
constexpr size_t CONCURRENCY_ALIGNMENT
并发结构对齐粒度(用于降低多核伪共享) / Alignment policy used by concurrency-oriented structures
Definition libxr_def.hpp:62
WriteOperation op
Write operation instance. 写入操作实例。