Operation Model
operation.hpp defines the generic Operation<T> template, which describes how the caller is notified when an asynchronous operation completes: callback (CALLBACK), blocking (BLOCK) or polling (POLLING).
ReadOperation / WriteOperation are aliases of Operation<ErrorCode> and are commonly used by I/O ports to report completion status via ErrorCode.
Operation Modes
OperationType
enum class OperationType : uint8_t {
CALLBACK, // Uses a callback function to handle completion
BLOCK, // Waits using a semaphore (blocking)
POLLING, // Uses a polling status variable
NONE // No completion handling
};
POLLING Status Enum
enum class OperationPollingStatus : uint32_t {
READY,
RUNNING,
DONE,
ERROR
};
Constructors
// Default constructor: type is NONE
Operation();
// Construct a blocking operation
Operation(Semaphore &sem, uint32_t timeout = UINT32_MAX);
// Construct a callback-based operation (T is the callback parameter type)
Operation(Callback<T> &cb);
// Construct a polling-based operation
Operation(std::atomic<OperationPollingStatus> &status);
An Operation can be copied and moved; copies refer to the same callback, semaphore or polling status.
Status Updates
template <typename Status>
void UpdateStatus(bool in_isr, Status&& status);
void MarkAsRunning();
UpdateStatus(...)triggers a callback, unblocks a waiter, or updates polling state depending on the operation type:- CALLBACK: calls
cb.Run(in_isr, status), passingstatusas the completion value of typeT. - BLOCK: calls
PostFromCallback(in_isr)on the semaphore to wake the waiter; the finalErrorCodeis kept by the port and returned by the blocking call. - POLLING: stores (release)
DONEwhenstatus == ErrorCode::OKandERRORotherwise, so it fits operations whose completion value is anErrorCode.
- CALLBACK: calls
MarkAsRunning()sets the polling status toRUNNINGif the type isPOLLING.- Ports or drivers call these two functions; users only construct the
Operationand pass it in. - An
Operationonly borrows its callback, semaphore or polling status; the caller keeps them valid until the operation ends. - A semaphore serves one BLOCK call at a time; BLOCK calls are thread-only.
- Callbacks run inline in the context that completes the I/O, possibly an ISR; read the polling status with
load(std::memory_order_acquire).
Usage Examples
Blocking write with timeout
Semaphore sem;
WriteOperation op_block(sem, 100);
write_port(data, op_block);
Callback-based completion feedback
auto cb = Callback<ErrorCode>::Create([](bool in_isr, int context, ErrorCode ec) {
// Callback logic
}, 123); // Binds context value 123
ReadOperation op_cb(cb);
read_port(buffer, op_cb);
Polling to check for completion
std::atomic<LibXR::ReadOperation::OperationPollingStatus> status{
LibXR::ReadOperation::OperationPollingStatus::READY};
ReadOperation op_poll(status);
read_port(buffer, op_poll);
// Later check if completed
auto now = status.load(std::memory_order_acquire);
if (now == LibXR::ReadOperation::OperationPollingStatus::DONE) {
// Completed successfully
} else if (now == LibXR::ReadOperation::OperationPollingStatus::ERROR) {
// Completed with an error
}
AsyncBlockWait
operation.hpp also defines AsyncBlockWait for driver internals: drivers that do not go through ReadPort / WritePort (such as some SPI and I2C drivers) use it to wait for a BLOCK transfer and hand off on timeout; see BLOCK Timeout and Completion Handoff.