libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
operation.hpp
1#pragma once
2
3#include <atomic>
4#include <cstdint>
5#include <type_traits>
6#include <utility>
7
8#include "libxr_cb.hpp"
9#include "libxr_def.hpp"
10#include "libxr_type.hpp"
11#include "semaphore.hpp"
12
13namespace LibXR
14{
15
23template <typename Args>
25{
26 public:
28
30 enum class OperationType : uint8_t
31 {
32 CALLBACK,
33 BLOCK,
34 POLLING,
35 NONE
36 };
37
40 enum class OperationPollingStatus : uint32_t
41 {
42 READY,
43 RUNNING,
44 DONE,
45 ERROR
46 };
47
50
59 Operation(Semaphore& sem, uint32_t timeout = UINT32_MAX)
60 : data{.sem_info = {&sem, timeout}}, type(OperationType::BLOCK)
61 {
62 }
63
69 : data{.callback = &callback}, type(OperationType::CALLBACK)
70 {
71 }
72
78 Operation(std::atomic<OperationPollingStatus>& status)
79 : data{.status = &status}, type(OperationType::POLLING)
80 {
81 }
82
84 Operation(const Operation&) = default;
86 Operation(Operation&&) noexcept = default;
87
92 Operation& operator=(const Operation&) = default;
93
98 Operation& operator=(Operation&&) noexcept = default;
99
110 template <typename Status>
111 void UpdateStatus(bool in_isr, Status&& status)
112 {
113 switch (type)
114 {
115 case OperationType::CALLBACK:
116 data.callback->Run(in_isr, std::forward<Status>(status));
117 break;
118 case OperationType::BLOCK:
119 // 信号量只负责唤醒,结果由调用方另行保存。
120 // The semaphore only wakes the caller; the result is stored separately.
121 data.sem_info.sem->PostFromCallback(in_isr);
122 break;
123 case OperationType::POLLING:
124 data.status->store((status == ErrorCode::OK) ? OperationPollingStatus::DONE
125 : OperationPollingStatus::ERROR,
126 std::memory_order_release);
127 break;
128 case OperationType::NONE:
129 break;
130 }
131 }
132
139 {
140 if (type == OperationType::POLLING)
141 {
142 data.status->store(OperationPollingStatus::RUNNING, std::memory_order_release);
143 }
144 }
145
147 union
148 {
150 struct
151 {
153 uint32_t timeout;
154 } sem_info;
156 std::atomic<OperationPollingStatus>* status;
157 } data;
158
161};
162
170{
171 public:
173 enum class State : uint32_t
174 {
175 IDLE = 0,
176 PENDING = 1,
177 CLAIMED = 2,
178 DETACHED = 3,
179 };
180
185 void Start(Semaphore& sem)
186 {
187 sem_ = &sem;
188 result_ = ErrorCode::OK;
189 state_.store(State::PENDING, std::memory_order_release);
190 }
191
193 void Cancel() { state_.store(State::IDLE, std::memory_order_release); }
194
202 ErrorCode Wait(uint32_t timeout)
203 {
204 DEV_ASSERT(sem_ != nullptr);
205 auto wait_ans = sem_->Wait(timeout);
206 if (wait_ans == ErrorCode::OK)
207 {
208 DEV_ASSERT(state_.load(std::memory_order_acquire) == State::CLAIMED);
209 state_.store(State::IDLE, std::memory_order_release);
210 return result_;
211 }
212
213 State expected = State::PENDING;
214 if (state_.compare_exchange_strong(expected, State::DETACHED,
215 std::memory_order_acq_rel,
216 std::memory_order_acquire))
217 {
218 return ErrorCode::TIMEOUT;
219 }
220
221 DEV_ASSERT(expected == State::CLAIMED || expected == State::DETACHED ||
222 expected == State::IDLE);
223 if (expected == State::DETACHED)
224 {
225 state_.store(State::IDLE, std::memory_order_release);
226 return ErrorCode::TIMEOUT;
227 }
228 if (expected == State::IDLE)
229 {
230 return ErrorCode::TIMEOUT;
231 }
232
233 ErrorCode finish_wait_ans;
234 do
235 {
236 finish_wait_ans = sem_->Wait(UINT32_MAX);
237 } while (finish_wait_ans == ErrorCode::TIMEOUT);
238 REQUIRE(finish_wait_ans == ErrorCode::OK);
239 state_.store(State::IDLE, std::memory_order_release);
240 return result_;
241 }
242
250 bool TryPost(bool in_isr, ErrorCode ec)
251 {
252 DEV_ASSERT_FROM_CALLBACK(sem_ != nullptr, in_isr);
253
254 State expected = State::PENDING;
255 if (!state_.compare_exchange_strong(expected, State::CLAIMED,
256 std::memory_order_acq_rel,
257 std::memory_order_acquire))
258 {
259 DEV_ASSERT_FROM_CALLBACK(expected == State::DETACHED || expected == State::IDLE,
260 in_isr);
261 if (expected == State::DETACHED)
262 {
263 expected = State::DETACHED;
264 (void)state_.compare_exchange_strong(
265 expected, State::IDLE, std::memory_order_acq_rel, std::memory_order_acquire);
266 }
267 return false;
268 }
269
270 result_ = ec;
271 sem_->PostFromCallback(in_isr);
272 return true;
273 }
274
275 private:
276 Semaphore* sem_ = nullptr;
277 std::atomic<State> state_{State::IDLE};
278 ErrorCode result_ = ErrorCode::OK;
279};
280
281class ReadPort;
282class WritePort;
283
286
289
290// RW 元数据存放在字节型 SPSC 环中,因此其指针/枚举操作描述必须保持可平凡复制。
291// Byte-backed SPSC storage requires trivially copyable operation descriptors.
292static_assert(std::is_trivially_copyable_v<ReadOperation>);
293static_assert(std::is_trivially_copyable_v<WriteOperation>);
294static_assert(std::is_trivially_destructible_v<ReadOperation>);
295static_assert(std::is_trivially_destructible_v<WriteOperation>);
296
303typedef void (*WriteFun)(WritePort& port, bool in_isr);
304
305} // namespace LibXR
同步驱动操作的阻塞等待器 / Blocking waiter for synchronous driver operations.
bool TryPost(bool in_isr, ErrorCode ec)
尝试认领完成并唤醒调用者 / Try to claim completion and wake the caller.
void Start(Semaphore &sem)
绑定信号量并开始等待 / Bind a semaphore and start waiting.
ErrorCode Wait(uint32_t timeout)
等待完成或超时交接 / Wait for completion or a timeout handoff.
State
32 位等待状态,兼容 STM32 原子适配 / 32-bit wait state for STM32 atomic support.
void Cancel()
清除等待状态,不发送通知 / Clear the wait state without posting.
通用回调包装,支持动态参数传递 / Generic callback wrapper supporting dynamic argument passing
Definition libxr_cb.hpp:143
操作的完成通知描述符 / Completion notification descriptor for an operation.
Definition operation.hpp:25
Operation(Semaphore &sem, uint32_t timeout=UINT32_MAX)
构造阻塞操作 / Construct a blocking operation.
Definition operation.hpp:59
Operation(const Operation &)=default
复制通知描述符,共用通知对象 / Copy the descriptor, sharing notification targets.
uint32_t timeout
等待超时值 / Wait timeout.
Operation(Operation &&) noexcept=default
移动描述符,源描述符保持不变 / Move the descriptor without clearing the source.
Operation(Callback &callback)
构造回调操作 / Construct a callback operation.
Definition operation.hpp:68
Operation()
构造无完成通知的操作 / Construct an operation without notification.
Definition operation.hpp:49
@ DONE
成功完成 / Completed successfully.
@ READY
尚未开始 / Not started.
@ RUNNING
正在执行 / In progress.
@ ERROR
错误结束 / Completed with an error.
union LibXR::Operation::@6 data
完成通知对象,由 type 选择有效成员 / Notification target selected by type.
void MarkAsRunning()
标记轮询操作正在执行 / Mark a polling operation as running.
Semaphore * sem
借用的信号量 / Borrowed semaphore.
Callback * callback
借用的回调对象 / Borrowed callback.
Operation(std::atomic< OperationPollingStatus > &status)
构造轮询操作 / Construct a polling operation.
Definition operation.hpp:78
OperationType type
当前通知方式 / Current notification mode.
OperationType
完成通知方式 / Completion notification mode.
Definition operation.hpp:31
@ BLOCK
信号量等待 / Wait with a semaphore.
@ NONE
无完成通知 / No completion notification.
@ CALLBACK
执行回调 / Invoke a callback.
@ POLLING
查询原子状态 / Poll an atomic status.
std::atomic< OperationPollingStatus > * status
借用的轮询状态 / Borrowed polling status.
信号量类,实现线程同步机制 Semaphore class implementing thread synchronization
Definition semaphore.hpp:23
基于 SPSC 字节队列的写端口 / Write endpoint backed by an SPSC byte queue.
LibXR 命名空间 / LibXR namespace.
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ PENDING
等待中 / Pending
@ OK
操作成功 / Operation successful