1#include "read_port.hpp"
16 ASSERT_FROM_CALLBACK(queue_data_ !=
nullptr, in_isr);
24 ASSERT_FROM_CALLBACK(!finished_, in_isr_);
27 ASSERT_FROM_CALLBACK(data !=
nullptr, in_isr_);
30 const ErrorCode result = port_.queue_data_->PushBatch(data, size);
44 ASSERT_FROM_CALLBACK(!finished_, in_isr_);
48 port_.PublishProduced(in_isr_);
54 return queue_data_ ==
nullptr ? 0U : queue_data_->
EmptySize();
59 return queue_data_ ==
nullptr ? 0U : queue_data_->
Size();
64 return queue_data_ ==
nullptr ? 0U : queue_data_->
MaxSize();
69bool ReadPort::TryClaimIdle()
71 uint32_t observed = state_.load(std::memory_order_acquire);
74 if (GetPhase(observed) != Phase::IDLE)
79 if (state_.compare_exchange_weak(observed,
static_cast<uint32_t
>(Phase::CLAIMED),
80 std::memory_order_acq_rel,
81 std::memory_order_acquire))
88bool ReadPort::HasEnough(
size_t available,
size_t requested)
const
90 return requested == 0U ? available != 0U : available >= requested;
93void ReadPort::ReleaseClaimed([[maybe_unused]]
bool in_isr)
95 uint32_t observed = state_.load(std::memory_order_acquire);
98 DEV_ASSERT_FROM_CALLBACK(GetPhase(observed) == Phase::CLAIMED, in_isr);
99 const uint32_t desired = WithPhase(observed, Phase::IDLE);
100 if (state_.compare_exchange_weak(observed, desired, std::memory_order_acq_rel,
101 std::memory_order_acquire))
108bool ReadPort::ClaimBlockCompletion()
110 uint32_t observed = state_.load(std::memory_order_acquire);
113 const Phase phase = GetPhase(observed);
114 if (phase == Phase::BLOCK_CLAIMED)
118 if (phase != Phase::CLAIMED && phase != Phase::CLAIMED_WITH_WAITER)
123 const uint32_t desired = WithPhase(observed, Phase::BLOCK_CLAIMED);
124 if (state_.compare_exchange_weak(observed, desired, std::memory_order_acq_rel,
125 std::memory_order_acquire))
132void ReadPort::ReleaseBlockCompletion([[maybe_unused]]
bool in_isr)
134 uint32_t observed = state_.load(std::memory_order_acquire);
137 DEV_ASSERT_FROM_CALLBACK(GetPhase(observed) == Phase::BLOCK_CLAIMED, in_isr);
138 const uint32_t desired = WithPhase(observed, Phase::IDLE);
139 if (state_.compare_exchange_weak(observed, desired, std::memory_order_acq_rel,
140 std::memory_order_acquire))
147void ReadPort::PublishProduced(
bool in_isr)
149 state_.fetch_or(EVENT_BIT, std::memory_order_acq_rel);
150 ProcessPendingReads(in_isr);
153void ReadPort::NotifyDataAvailable(
bool in_isr)
155 state_.fetch_or(EVENT_BIT, std::memory_order_acq_rel);
156 ProcessPendingReads(in_isr);
171 const bool is_block = op.
type == ReadOperation::OperationType::BLOCK;
173 if (data.
size_ != 0U)
175 ASSERT_FROM_CALLBACK(data.
addr_ !=
nullptr, in_isr);
178 ReleaseClaimed(in_isr);
183 if (HasEnough(queue_data_->
Size(), data.
size_))
185 if (data.
size_ != 0U)
187 [[maybe_unused]]
const auto pop_batch_result =
189 DEV_ASSERT_FROM_CALLBACK(pop_batch_result ==
ErrorCode::OK, in_isr);
192 Request completed{data, op};
193 ReleaseClaimed(in_isr);
194 if (data.
size_ != 0U)
198 if (completed.op.type != ReadOperation::OperationType::BLOCK)
205 info_ = Request{data, op};
210 uint32_t observed = state_.load(std::memory_order_acquire);
211 DEV_ASSERT_FROM_CALLBACK(GetPhase(observed) == Phase::CLAIMED, in_isr);
213 if (HasEvent(observed))
215 if (!state_.compare_exchange_weak(observed,
static_cast<uint32_t
>(Phase::CLAIMED),
216 std::memory_order_acq_rel,
217 std::memory_order_acquire))
222 if (HasEnough(queue_data_->
Size(), data.
size_))
224 if (info_.op.
type == ReadOperation::OperationType::BLOCK)
226 CompleteClaimedBlock(in_isr);
227 return WaitForBlock(op);
229 CompleteClaimedRead(in_isr);
235 uint32_t expected = observed;
236 if (state_.compare_exchange_weak(expected,
static_cast<uint32_t
>(Phase::PENDING),
237 std::memory_order_acq_rel,
238 std::memory_order_acquire))
247void ReadPort::ProcessPendingReads(
bool in_isr)
251 uint32_t observed = state_.load(std::memory_order_acquire);
252 if (GetPhase(observed) != Phase::PENDING)
257 if (!state_.compare_exchange_weak(observed,
static_cast<uint32_t
>(Phase::CLAIMED),
258 std::memory_order_acq_rel,
259 std::memory_order_acquire))
264 if (!HasEnough(queue_data_->
Size(), info_.data.
size_))
268 uint32_t current = state_.load(std::memory_order_acquire);
269 const Phase current_phase = GetPhase(current);
270 if (current_phase == Phase::CLAIMED_WITH_WAITER)
273 DEV_ASSERT_FROM_CALLBACK(waiter !=
nullptr, in_isr);
274 const uint32_t desired = WithPhase(current, Phase::IDLE);
275 if (state_.compare_exchange_weak(current, desired, std::memory_order_acq_rel,
276 std::memory_order_acquire))
284 DEV_ASSERT_FROM_CALLBACK(current_phase == Phase::CLAIMED, in_isr);
285 const uint32_t desired = WithPhase(current, Phase::PENDING);
286 if (state_.compare_exchange_weak(current, desired, std::memory_order_acq_rel,
287 std::memory_order_acquire))
289 if (HasEvent(desired))
299 if (info_.op.
type == ReadOperation::OperationType::BLOCK)
301 CompleteClaimedBlock(in_isr);
305 CompleteClaimedRead(in_isr);
311void ReadPort::CompleteClaimedRead(
bool in_isr)
313 Request completed = info_;
314 DEV_ASSERT_FROM_CALLBACK(completed.op.type != ReadOperation::OperationType::BLOCK,
317 if (completed.data.size_ != 0U)
319 [[maybe_unused]]
const auto pop_batch_result = queue_data_->
PopBatch(
320 reinterpret_cast<uint8_t*
>(completed.data.addr_), completed.data.size_);
321 DEV_ASSERT_FROM_CALLBACK(pop_batch_result ==
ErrorCode::OK, in_isr);
324 ReleaseClaimed(in_isr);
325 if (completed.data.size_ != 0U)
332void ReadPort::CompleteClaimedBlock(
bool in_isr)
334 Request completed = info_;
335 DEV_ASSERT_FROM_CALLBACK(completed.op.type == ReadOperation::OperationType::BLOCK,
337 [[maybe_unused]]
const auto claim_block_completion_result = ClaimBlockCompletion();
338 DEV_ASSERT_FROM_CALLBACK(claim_block_completion_result, in_isr);
340 if (completed.data.size_ != 0U)
342 [[maybe_unused]]
const auto pop_batch_result = queue_data_->
PopBatch(
343 reinterpret_cast<uint8_t*
>(completed.data.addr_), completed.data.size_);
344 DEV_ASSERT_FROM_CALLBACK(pop_batch_result ==
ErrorCode::OK, in_isr);
349 completed.op.data.sem_info.sem->PostFromCallback(in_isr);
357 DEV_ASSERT(GetPhase(state_.load(std::memory_order_acquire)) == Phase::BLOCK_CLAIMED);
359 ReleaseBlockCompletion(
false);
365 uint32_t observed = state_.load(std::memory_order_acquire);
366 const Phase phase = GetPhase(observed);
367 if (phase == Phase::PENDING)
369 const uint32_t desired = WithPhase(observed, Phase::IDLE);
370 if (state_.compare_exchange_weak(observed, desired, std::memory_order_acq_rel,
371 std::memory_order_acquire))
378 if (phase == Phase::CLAIMED)
380 const uint32_t desired = WithPhase(observed, Phase::CLAIMED_WITH_WAITER);
381 if (state_.compare_exchange_weak(observed, desired, std::memory_order_acq_rel,
382 std::memory_order_acquire))
389 DEV_ASSERT(phase == Phase::CLAIMED_WITH_WAITER || phase == Phase::BLOCK_CLAIMED);
395 wait_result = op.
data.sem_info.
sem->
Wait(UINT32_MAX);
398 const Phase completed_phase = GetPhase(state_.load(std::memory_order_acquire));
399 if (completed_phase == Phase::IDLE)
404 DEV_ASSERT(completed_phase == Phase::BLOCK_CLAIMED);
406 ReleaseBlockCompletion(
false);
421 queue_data_->
Reset();
422 ReleaseClaimed(in_isr);
429 DEV_ASSERT(queue !=
nullptr);
430 DEV_ASSERT(queue_data_ ==
nullptr);
uint32_t timeout
等待超时值 / Wait timeout.
union LibXR::Operation::@6 data
完成通知对象,由 type 选择有效成员 / Notification target selected by type.
void MarkAsRunning()
标记轮询操作正在执行 / Mark a polling operation as running.
Semaphore * sem
借用的信号量 / Borrowed semaphore.
OperationType type
当前通知方式 / Current notification mode.
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
接收队列的短期写入接口 / Short-lived producer interface for the RX queue.
void Publish()
结束本次写入并通知挂起读 / End production and notify a pending read.
size_t EmptySize() const
获取接收队列当前空闲空间 / Get current RX queue free space.
~ReadQueue()
开发期检查是否已 Publish / Check for Publish in development builds.
ErrorCode PushBatch(const uint8_t *data, size_t size)
批量复制字节到接收队列 / Copy a batch of bytes into the RX queue.
size_t Capacity() const
获取接收队列容量 / Get the RX queue capacity.
virtual void OnReadQueueSpaceAvailable(bool)
接收队列空间可用通知 / RX queue space-available notification.
ReadPort(size_t buffer_size=128U)
构造读端口并分配接收队列 / Construct a read port and allocate its RX queue.
size_t EmptySize() const
获取当前空闲空间 / Get current free space.
ErrorCode ClearQueuedData(bool in_isr=false)
丢弃当前已排队的接收字节 / Discard currently queued RX bytes.
size_t Size() const
获取当前排队的数据量 / Get the current queued data size.
bool Readable() const
检查端口是否支持读取 / Check whether the port supports reads.
size_t Capacity() const
获取接收队列容量 / Get the RX queue capacity.
ErrorCode operator()(RawData data, ReadOperation &op, bool in_isr=false)
提交读请求 / Submit a read request.
ReadQueue GetReadQueue(bool in_isr=false)
获取后端接收入队接口 / Obtain the backend RX producer interface.
size_t MaxSize() const
获取队列最大容量 / Get the maximum queue capacity
size_t Size() const
获取当前已用元素数 / Get the current element count
size_t EmptySize() const
获取剩余空槽数 / Get the current free-slot count
单生产者单消费者无锁队列 / Single-producer single-consumer lock-free queue.
void Reset()
从 consumer 侧丢弃当前可见的全部 payload / Discard currently available payloads from the consumer side
ErrorCode PopBatch(Data *data, size_t size)
批量弹出多个 payload / Pop multiple payloads from the queue.
信号量类,实现线程同步机制 Semaphore class implementing thread synchronization
void PostFromCallback(bool in_isr)
从中断回调中释放(增加)信号量 Releases (increments) the semaphore from an ISR (Interrupt Service Routine)
ErrorCode Wait(uint32_t timeout=UINT32_MAX)
等待(减少)信号量 Waits (decrements) the semaphore
LibXR 命名空间 / LibXR namespace.
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ SIZE_ERR
尺寸错误 / Size error
@ NOT_SUPPORT
不支持 / Not supported
@ OK
操作成功 / Operation successful
constexpr size_t CONCURRENCY_ALIGNMENT
并发结构对齐粒度(用于降低多核伪共享) / Alignment policy used by concurrency-oriented structures