libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
write_port.hpp
1#pragma once
2
3#include <algorithm>
4#include <atomic>
5#include <cstddef>
6#include <cstdint>
7#include <string_view>
8#include <type_traits>
9#include <utility>
10
11#include "operation.hpp"
12#include "queue.hpp"
13
14namespace LibXR
15{
16
17class Pipe;
18
40{
41 private:
43 enum class Phase : uint32_t
44 {
45 IDLE = 0U,
46 LOCKED = 1U,
47 BLOCK_WAITING = 2U,
48 BLOCK_CLAIMED = 3U,
49 BLOCK_DETACHED = 4U,
51 BLOCK_RETIRE_WAITING = 5U,
52 };
53
55 static constexpr uint32_t PHASE_BITS = 3U;
56 static constexpr uint32_t PHASE_MASK = (1U << PHASE_BITS) - 1U;
58 static constexpr uint32_t RELEASED_INCREMENT = 1U << PHASE_BITS;
60 static constexpr uint32_t MAX_RELEASED_REQUESTS = UINT32_MAX >> PHASE_BITS;
61
62 static_assert(static_cast<uint32_t>(Phase::BLOCK_RETIRE_WAITING) <= PHASE_MASK);
63
65 struct Request
66 {
67 size_t size;
69 };
70
71 static_assert(std::is_trivially_copyable_v<Request>);
72 static_assert(std::is_trivially_destructible_v<Request>);
73
75 static constexpr uint32_t MakeState(Phase phase, uint32_t released)
76 {
77 return (released << PHASE_BITS) | static_cast<uint32_t>(phase);
78 }
79
81 static Phase GetPhase(uint32_t state) { return static_cast<Phase>(state & PHASE_MASK); }
82
84 static uint32_t GetReleasedCount(uint32_t state) { return state >> PHASE_BITS; }
85
87 static uint32_t WithPhase(uint32_t state, Phase phase)
88 {
89 return (state & ~PHASE_MASK) | static_cast<uint32_t>(phase);
90 }
91
93 static size_t ValidateQueueSize(size_t queue_size)
94 {
95 ASSERT(queue_size <= MAX_RELEASED_REQUESTS);
96 return queue_size;
97 }
98
100 [[nodiscard]] bool IsAdmissionMode() const { return queue_requests_ == nullptr; }
102 [[nodiscard]] Phase LoadPhase() const
103 {
104 return GetPhase(state_.load(std::memory_order_acquire));
105 }
107 [[nodiscard]] bool TryClaimProducer();
109 [[nodiscard]] bool TryRegisterRetirementWait(WriteOperation& op);
111 [[nodiscard]] ErrorCode WaitForRetirement(WriteOperation& op);
113 [[nodiscard]] ErrorCode CommitQueued(size_t size, WriteOperation& op, bool in_isr);
115 [[nodiscard]] ErrorCode CommitAdmission(size_t size, WriteOperation& op, bool in_isr);
117 [[nodiscard]] ErrorCode WaitForBlock(WriteOperation& op);
119 void ReleaseProducer(Phase next, bool in_isr);
121 void PublishQueuedRequest(Phase next, bool in_isr);
123 void DecrementReleasedRequest(bool in_isr);
125 void NotifyBackend(bool in_isr);
127 void SettleWriteQueue(size_t accepted, ErrorCode result, bool in_isr) noexcept;
129 void CompleteRequest(Request& request, ErrorCode result, bool in_isr);
130
131 friend class Pipe;
132
133 public:
154 {
155 public:
156 WriteQueue(const WriteQueue&) = delete;
157 WriteQueue& operator=(const WriteQueue&) = delete;
158 WriteQueue(WriteQueue&&) = delete;
159 WriteQueue& operator=(WriteQueue&&) = delete;
161 ~WriteQueue() noexcept;
162
167 [[nodiscard]] size_t AvailableSize() const
168 {
169 DEV_ASSERT_FROM_CALLBACK(popped_size_ <= front_size_, in_isr_);
170 return front_size_ - popped_size_;
171 }
172
178 [[nodiscard]] bool Empty() const { return AvailableSize() == 0U; }
179
190 void PopAll(uint8_t* destination);
191
213 template <typename Writer>
214 size_t PopWithWriter(size_t limit, Writer&& writer)
215 {
216 BeginAction();
217 const size_t offered = std::min(limit, AvailableSize());
218 if (offered == 0U)
219 {
220 return 0U;
221 }
222
223 const size_t accepted = port_.queue_data_->ConsumeWithReader(
224 offered,
225 [&](const uint8_t* first, size_t first_size, const uint8_t* second,
226 size_t second_size) -> size_t
227 {
228 const size_t accepted = writer(first, first_size, second, second_size);
229 ASSERT_FROM_CALLBACK(accepted <= first_size + second_size, in_isr_);
230 return accepted;
231 });
232 popped_size_ += accepted;
233 return accepted;
234 }
235
246 void FailFront(ErrorCode reason);
247
248 private:
249 friend class WritePort;
250
252 void BeginAction()
253 {
254 ASSERT_FROM_CALLBACK(!action_used_, in_isr_);
255 action_used_ = true;
256 }
257
259 WriteQueue(WritePort& port, bool in_isr, size_t front_size)
260 : port_(port), in_isr_(in_isr), front_size_(front_size)
261 {
262 }
263
264 WritePort& port_;
265 const bool in_isr_;
266 const size_t front_size_;
268 size_t popped_size_ = 0U;
269 ErrorCode settlement_result_ = ErrorCode::OK;
271 bool action_used_ = false;
272 };
273
294 class Stream
295 {
296 public:
305
313 ~Stream();
314
315 Stream(const Stream&) = delete;
316 Stream& operator=(const Stream&) = delete;
317 Stream(Stream&&) = delete;
318 Stream& operator=(Stream&&) = delete;
319
333 [[nodiscard]] ErrorCode Write(ConstRawData data);
334
340 [[nodiscard]] ErrorCode Write(std::string_view text)
341 {
342 return Write(ConstRawData{text.data(), text.size()});
343 }
344
353 Stream& operator<<(const ConstRawData& data);
354
368 [[nodiscard]] ErrorCode Commit();
369
382 [[nodiscard]] ErrorCode Acquire();
383
391 [[nodiscard]] size_t EmptySize() const
392 {
393 return owns_port_ && port_ != nullptr && port_->queue_data_ != nullptr
394 ? port_->queue_data_->EmptySize()
395 : 0U;
396 }
397
398 private:
400 [[nodiscard]] ErrorCode SubmitBuffered();
402 void Release();
404 void CompleteEmpty();
405
406 WritePort* port_ = nullptr;
407 WriteOperation op_;
409 size_t buffered_size_ = 0U;
411 bool owns_port_ = false;
412 };
413
425 WritePort(size_t queue_size = 3U, size_t buffer_size = 128U);
426
434 [[nodiscard]] size_t EmptySize() const;
435
443 [[nodiscard]] size_t Size() const;
444
449 [[nodiscard]] size_t Capacity() const;
450
456 [[nodiscard]] bool Writable() const;
457
473
486 [[nodiscard]] WriteQueue GetWriteQueue(bool in_isr = false);
487
535 ErrorCode operator()(ConstRawData data, WriteOperation& op, bool in_isr = false);
536
537 private:
539 SPSCQueue<Request>* queue_requests_;
541 SPSCQueue<uint8_t>* queue_data_;
543 WriteFun write_fun_ = nullptr;
544
547 std::atomic<uint32_t> state_{MakeState(Phase::IDLE, 0U)};
549 ErrorCode block_result_ = ErrorCode::OK;
551 size_t front_remaining_ = 0U;
554 Semaphore* admission_waiter_ = nullptr;
555};
556
557} // namespace LibXR
只读原始数据视图 / Immutable raw data view
由读写端口组成的单向管道 / Unidirectional pipe connecting read and write ports.
size_t EmptySize() const
获取剩余空槽数 / Get the current free-slot count
单生产者单消费者无锁队列 / Single-producer single-consumer lock-free queue.
size_t ConsumeWithReader(size_t limit, Reader &&reader)
通过一次双 span 回调消费 payload 前缀 / Consume a payload prefix through one two-span reader callback.
合并多次写入的流接口 / Stream interface for batched writes.
ErrorCode Acquire()
尝试取得端口写入权 / Try to acquire the port's producer access.
ErrorCode Commit()
提交批次并释放写入权 / Submit the batch and release producer access.
size_t EmptySize() const
获取当前批次可追加的空间 / Get current free space for appending.
Stream(WritePort *port, WriteOperation op)
构造流并尝试取得写入权 / Construct a stream and try to acquire the port.
~Stream()
提交剩余批次并结束流 / Submit the remaining batch and destroy the stream.
ErrorCode Write(ConstRawData data)
向当前批次追加数据 / Append data to the current batch.
ErrorCode Write(std::string_view text)
向当前批次追加文本 / Append text to the current batch.
Stream & operator<<(const ConstRawData &data)
尝试追加数据并返回流引用 / Try to append data and return the stream.
已提交队头的出队接口 / Consumer interface for one released front.
void FailFront(ErrorCode reason)
丢弃剩余数据并结束队头 / Discard the remainder and fail the front.
size_t PopWithWriter(size_t limit, Writer &&writer)
通过回调取走队头前缀 / Consume a front prefix through a callback.
void PopAll(uint8_t *destination)
复制并取走队头剩余数据 / Copy and consume the entire front remainder.
~WriteQueue() noexcept
结算出队,使用获取时的上下文 / Settle progress using the captured context.
bool Empty() const
检查本接口是否还有数据 / Check whether this interface has remaining data.
size_t AvailableSize() const
获取当前队头的剩余长度 / Get the current front remainder.
基于 SPSC 字节队列的写端口 / Write endpoint backed by an SPSC byte queue.
WriteQueue GetWriteQueue(bool in_isr=false)
获取已提交队头的出队接口 / Obtain a consumer interface for the released front.
bool Writable() const
检查端口是否支持写入 / Check whether the port supports writes.
size_t Size() const
获取字节队列当前数据量 / Get current byte queue occupancy.
WritePort & operator=(WriteFun fun)
绑定写入进度通知函数 / Bind the write progress notification function.
size_t Capacity() const
获取字节队列总容量 / Get total byte queue capacity.
WritePort(size_t queue_size=3U, size_t buffer_size=128U)
构造写端口并分配队列 / Construct a write port and allocate its queues.
Definition write_port.cpp:8
size_t EmptySize() const
获取字节队列当前空闲空间 / Get current byte queue free space.
ErrorCode operator()(ConstRawData data, WriteOperation &op, bool in_isr=false)
提交写请求 / Submit a write request.
LibXR 命名空间 / LibXR namespace.
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ OK
操作成功 / Operation successful
void(* WriteFun)(WritePort &port, bool in_isr)
写入进度通知函数类型 / Write progress notification function type.