1#include "write_port.hpp"
9 : queue_requests_(queue_size != 0U
11 SPSCQueue<Request>(ValidateQueueSize(queue_size))
21 return queue_data_ ==
nullptr ? 0U : queue_data_->
EmptySize();
26 return queue_data_ ==
nullptr ? 0U : queue_data_->
Size();
31 return queue_data_ ==
nullptr ? 0U : queue_data_->
MaxSize();
36 return queue_data_ !=
nullptr && write_fun_ !=
nullptr;
45bool WritePort::TryClaimProducer()
47 uint32_t observed = state_.load(std::memory_order_acquire);
50 if (GetPhase(observed) != Phase::IDLE)
55 const uint32_t desired = WithPhase(observed, Phase::LOCKED);
56 if (state_.compare_exchange_weak(observed, desired, std::memory_order_acq_rel,
57 std::memory_order_acquire))
64void WritePort::ReleaseProducer(Phase next, [[maybe_unused]]
bool in_isr)
66 uint32_t observed = state_.load(std::memory_order_acquire);
69 DEV_ASSERT_FROM_CALLBACK(GetPhase(observed) == Phase::LOCKED, in_isr);
70 const uint32_t desired = WithPhase(observed, next);
71 if (state_.compare_exchange_weak(observed, desired, std::memory_order_acq_rel,
72 std::memory_order_acquire))
79void WritePort::PublishQueuedRequest(Phase next, [[maybe_unused]]
bool in_isr)
81 uint32_t observed = state_.load(std::memory_order_acquire);
84 DEV_ASSERT_FROM_CALLBACK(GetPhase(observed) == Phase::LOCKED, in_isr);
85 const uint32_t released = GetReleasedCount(observed);
86 DEV_ASSERT_FROM_CALLBACK(released < MAX_RELEASED_REQUESTS, in_isr);
87 const uint32_t desired = MakeState(next, released + 1U);
88 if (state_.compare_exchange_weak(observed, desired, std::memory_order_acq_rel,
89 std::memory_order_acquire))
96void WritePort::DecrementReleasedRequest([[maybe_unused]]
bool in_isr)
98 uint32_t observed = state_.load(std::memory_order_acquire);
101 DEV_ASSERT_FROM_CALLBACK(GetReleasedCount(observed) != 0U, in_isr);
102 const uint32_t desired = observed - RELEASED_INCREMENT;
103 if (state_.compare_exchange_weak(observed, desired, std::memory_order_acq_rel,
104 std::memory_order_acquire))
111void WritePort::NotifyBackend(
bool in_isr)
113 if (write_fun_ !=
nullptr)
115 write_fun_(*
this, in_isr);
121 ASSERT_FROM_CALLBACK(queue_requests_ !=
nullptr, in_isr);
123 if (GetReleasedCount(state_.load(std::memory_order_acquire)) == 0U)
125 DEV_ASSERT_FROM_CALLBACK(front_remaining_ == 0U, in_isr);
130 [[maybe_unused]]
const auto peek_result = queue_requests_->
Peek(request);
131 DEV_ASSERT_FROM_CALLBACK(peek_result ==
ErrorCode::OK, in_isr);
132 if (front_remaining_ == 0U)
134 DEV_ASSERT_FROM_CALLBACK(request.size != 0U, in_isr);
135 front_remaining_ = request.size;
139 DEV_ASSERT_FROM_CALLBACK(front_remaining_ <= request.size, in_isr);
142 return WriteQueue(*
this, in_isr, front_remaining_);
149 DEV_ASSERT_FROM_CALLBACK(remaining != 0U, in_isr_);
150 DEV_ASSERT_FROM_CALLBACK(destination !=
nullptr, in_isr_);
155 [destination, &offset](
const uint8_t* first,
size_t first_size,
156 const uint8_t* second,
size_t second_size) ->
size_t
158 if (first_size != 0U)
160 std::memcpy(destination + offset, first, first_size);
161 offset += first_size;
163 if (second_size != 0U)
165 std::memcpy(destination + offset, second, second_size);
166 offset += second_size;
168 return first_size + second_size;
170 DEV_ASSERT_FROM_CALLBACK(accepted == remaining, in_isr_);
171 popped_size_ += accepted;
178 DEV_ASSERT_FROM_CALLBACK(front_size_ != 0U, in_isr_);
180 const size_t remaining = AvailableSize();
181 DEV_ASSERT_FROM_CALLBACK(remaining != 0U, in_isr_);
182 const size_t accepted = port_.queue_data_->ConsumeWithReader(
184 [](
const uint8_t* first,
size_t first_size,
const uint8_t* second,
185 size_t second_size) ->
size_t
189 return first_size + second_size;
191 DEV_ASSERT_FROM_CALLBACK(accepted == remaining, in_isr_);
192 popped_size_ += accepted;
193 settlement_result_ = reason;
198 port_.SettleWriteQueue(popped_size_, settlement_result_, in_isr_);
201void WritePort::SettleWriteQueue(
size_t accepted,
ErrorCode result,
bool in_isr)
noexcept
208 DEV_ASSERT_FROM_CALLBACK(queue_requests_ !=
nullptr, in_isr);
209 DEV_ASSERT_FROM_CALLBACK(accepted <= front_remaining_, in_isr);
210 front_remaining_ -= accepted;
211 if (front_remaining_ != 0U)
217 [[maybe_unused]]
const auto pop_result = queue_requests_->
Pop(completed);
218 DEV_ASSERT_FROM_CALLBACK(pop_result ==
ErrorCode::OK, in_isr);
219 DecrementReleasedRequest(in_isr);
220 CompleteRequest(completed, result, in_isr);
223void WritePort::CompleteRequest(Request& request,
ErrorCode result,
bool in_isr)
225 if (request.op.type != WriteOperation::OperationType::BLOCK)
227 request.op.UpdateStatus(in_isr, result);
233 uint32_t observed = state_.load(std::memory_order_acquire);
234 const Phase phase = GetPhase(observed);
235 if (phase == Phase::BLOCK_WAITING)
237 const uint32_t desired = WithPhase(observed, Phase::BLOCK_CLAIMED);
238 if (!state_.compare_exchange_weak(observed, desired, std::memory_order_acq_rel,
239 std::memory_order_acquire))
244 block_result_ = result;
245 request.op.data.sem_info.sem->PostFromCallback(in_isr);
249 if (phase == Phase::BLOCK_DETACHED)
251 const uint32_t desired = WithPhase(observed, Phase::IDLE);
252 if (!state_.compare_exchange_weak(observed, desired, std::memory_order_acq_rel,
253 std::memory_order_acquire))
260 if (phase == Phase::BLOCK_RETIRE_WAITING)
262 const uint32_t desired = WithPhase(observed, Phase::LOCKED);
263 if (!state_.compare_exchange_weak(observed, desired, std::memory_order_acq_rel,
264 std::memory_order_acquire))
270 admission_waiter_ =
nullptr;
271 DEV_ASSERT_FROM_CALLBACK(waiter !=
nullptr, in_isr);
276 DEV_ASSERT_FROM_CALLBACK(
false, in_isr);
283 DEV_ASSERT_FROM_CALLBACK(queue_requests_ !=
nullptr, in_isr);
284 DEV_ASSERT_FROM_CALLBACK(queue_data_ !=
nullptr, in_isr);
285 DEV_ASSERT_FROM_CALLBACK(size != 0U, in_isr);
287 Request request{size, op};
288 [[maybe_unused]]
const auto push_result = queue_requests_->
Push(request);
289 DEV_ASSERT_FROM_CALLBACK(push_result ==
ErrorCode::OK, in_isr);
290 request.op.MarkAsRunning();
292 PublishQueuedRequest(op.
type == WriteOperation::OperationType::BLOCK
293 ? Phase::BLOCK_WAITING
296 NotifyBackend(in_isr);
298 return op.
type == WriteOperation::OperationType::BLOCK ? WaitForBlock(op)
305 DEV_ASSERT_FROM_CALLBACK(IsAdmissionMode(), in_isr);
306 DEV_ASSERT_FROM_CALLBACK(size != 0U, in_isr);
310 NotifyBackend(in_isr);
311 ReleaseProducer(Phase::IDLE, in_isr);
313 if (completed.
type != WriteOperation::OperationType::BLOCK)
322 DEV_ASSERT(op.
type == WriteOperation::OperationType::BLOCK);
323 admission_waiter_ = op.
data.sem_info.
sem;
324 uint32_t observed = state_.load(std::memory_order_acquire);
327 if (GetPhase(observed) != Phase::BLOCK_DETACHED)
329 admission_waiter_ =
nullptr;
333 const uint32_t desired = WithPhase(observed, Phase::BLOCK_RETIRE_WAITING);
334 if (state_.compare_exchange_weak(observed, desired, std::memory_order_acq_rel,
335 std::memory_order_acquire))
344 if (!TryRegisterRetirementWait(op))
346 if (LoadPhase() == Phase::IDLE && TryClaimProducer())
356 DEV_ASSERT(LoadPhase() == Phase::LOCKED);
362 uint32_t observed = state_.load(std::memory_order_acquire);
363 const Phase phase = GetPhase(observed);
364 if (phase == Phase::BLOCK_RETIRE_WAITING)
366 const uint32_t desired = WithPhase(observed, Phase::BLOCK_DETACHED);
367 if (state_.compare_exchange_weak(observed, desired, std::memory_order_acq_rel,
368 std::memory_order_acquire))
370 admission_waiter_ =
nullptr;
376 DEV_ASSERT(phase == Phase::LOCKED);
382 wait_result = op.
data.sem_info.
sem->
Wait(UINT32_MAX);
385 ReleaseProducer(Phase::IDLE,
false);
394 DEV_ASSERT(LoadPhase() == Phase::BLOCK_CLAIMED);
396 uint32_t observed = state_.load(std::memory_order_acquire);
399 DEV_ASSERT(GetPhase(observed) == Phase::BLOCK_CLAIMED);
400 const uint32_t desired = WithPhase(observed, Phase::IDLE);
401 if (state_.compare_exchange_weak(observed, desired, std::memory_order_acq_rel,
402 std::memory_order_acquire))
412 uint32_t observed = state_.load(std::memory_order_acquire);
413 const Phase phase = GetPhase(observed);
414 if (phase == Phase::BLOCK_WAITING)
416 const uint32_t desired = WithPhase(observed, Phase::BLOCK_DETACHED);
417 if (state_.compare_exchange_weak(observed, desired, std::memory_order_acq_rel,
418 std::memory_order_acquire))
425 DEV_ASSERT(phase == Phase::BLOCK_CLAIMED);
431 wait_result = op.
data.sem_info.
sem->
Wait(UINT32_MAX);
435 uint32_t observed = state_.load(std::memory_order_acquire);
438 DEV_ASSERT(GetPhase(observed) == Phase::BLOCK_CLAIMED);
439 const uint32_t desired = WithPhase(observed, Phase::IDLE);
440 if (state_.compare_exchange_weak(observed, desired, std::memory_order_acq_rel,
441 std::memory_order_acquire))
456 if (data.
size_ == 0U)
458 if (op.
type != WriteOperation::OperationType::BLOCK)
465 if (!TryClaimProducer())
467 if (op.
type == WriteOperation::OperationType::BLOCK &&
468 LoadPhase() == Phase::BLOCK_DETACHED && data.
size_ <=
Capacity())
470 const ErrorCode retirement = WaitForRetirement(op);
482 ASSERT_FROM_CALLBACK(data.
addr_ !=
nullptr, in_isr);
485 (!IsAdmissionMode() && queue_requests_->
EmptySize() < 1U))
487 ReleaseProducer(Phase::IDLE, in_isr);
491 [[maybe_unused]]
const auto push_batch_result =
493 DEV_ASSERT_FROM_CALLBACK(push_batch_result ==
ErrorCode::OK, in_isr);
495 return IsAdmissionMode() ? CommitAdmission(data.
size_, op, in_isr)
496 : CommitQueued(data.
size_, op, in_isr);
只读原始数据视图 / Immutable raw data view
size_t size_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address
uint32_t timeout
等待超时值 / Wait timeout.
void UpdateStatus(bool in_isr, Status &&status)
按通知方式报告完成结果 / Report completion using the selected mode.
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.
ErrorCode Push(const Data &item)
推入一个强类型元素 / Push one typed element.
ErrorCode Pop(Data &item)
弹出一个强类型元素 / Pop one typed element.
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.
ErrorCode Peek(Data &item)
查看一个队头 payload 但不出队 / Peek one front payload without dequeuing it.
size_t ConsumeWithReader(size_t limit, Reader &&reader)
通过一次双 span 回调消费 payload 前缀 / Consume a payload prefix through one two-span reader callback.
ErrorCode PushBatch(const Data *data, size_t size)
批量推入多个 payload / Push multiple payloads into 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
已提交队头的出队接口 / Consumer interface for one released front.
void FailFront(ErrorCode reason)
丢弃剩余数据并结束队头 / Discard the remainder and fail the front.
void PopAll(uint8_t *destination)
复制并取走队头剩余数据 / Copy and consume the entire front remainder.
~WriteQueue() noexcept
结算出队,使用获取时的上下文 / Settle progress using the captured context.
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.
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.
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ NOT_SUPPORT
不支持 / Not supported
@ OK
操作成功 / Operation successful
constexpr size_t CONCURRENCY_ALIGNMENT
并发结构对齐粒度(用于降低多核伪共享) / Alignment policy used by concurrency-oriented structures
void(* WriteFun)(WritePort &port, bool in_isr)
写入进度通知函数类型 / Write progress notification function type.