IO Read/Write Abstraction
This module defines the generic ReadPort
and WritePort
interface classes for cross-platform encapsulation of various I/O behaviors such as asynchronous, blocking, and polling. It binds completion feedback mechanisms via the Operation
model. To adapt to different underlying drivers, simply implement the corresponding read/write functions and assign them to the port object to gain full asynchronous I/O capability.
ReadPort
, WritePort
, and WritePort::Stream
are implemented using atomic operations and lock-free data structures, enabling the entire read and write process to be performed without any system calls, while still ensuring thread safety. The "locks" mentioned below are purely logical abstractions and do not involve any actual mutex operations.
Core Types
ReadPort / WritePort
ReadPort
and WritePort
encapsulate the invocation process, buffer management, and synchronization mechanisms for read/write operations. Each call is accompanied by an Operation
instance to explicitly specify the desired completion feedback behavior (callback, blocking, polling, or ignore).
ReadOperation / WriteOperation
typedef Operation<ErrorCode> ReadOperation;
typedef Operation<ErrorCode> WriteOperation;
These represent asynchronous I/O operations with a completion response behavior. Callbacks, semaphores, or polling status variables can be passed via the constructor—see the core-operation
page for details.
ReadPort Interface
Initialization
ReadPort(size_t buffer_size = 128);
Constructor that allocates the receive buffer, with a default size of 128 bytes.
Set Read Function
ReadPort &operator=(ReadFun fun);
Sets the read function pointer, usually called by the underlying driver—users typically don’t need to manage this.
Submit Read Request
ErrorCode operator()(RawData data, ReadOperation &op);
Requests to read data.size_
bytes; blocks, polls, or invokes a callback depending on op
.
State Check
size_t Size();
size_t EmptySize();
bool Readable();
Used to check buffer status and whether data is available to read.
Process Pending Reads
void ProcessPendingReads(bool in_isr);
Actively checks and completes previously pending read operations. Typically invoked by the driver after new data arrives.
Reset State
void Reset();
Clears the buffer and internal state.
WritePort Interface
Initialization
WritePort(size_t queue_size = 3, size_t buffer_size = 128);
Constructor that allocates the write queue and buffer, supporting queuing of multiple write requests.
Set Write Function
WritePort &operator=(WriteFun fun);
Sets the write function pointer, usually assigned by the underlying driver.
Submit Write Request
ErrorCode operator()(ConstRawData data, WriteOperation &op);
Adds data to the write queue and handles completion based on the behavior of op
.
State Check
size_t Size();
size_t EmptySize();
bool Writable();
Checks buffer space and whether data can be written.
Reset State
void Reset();
Clears the write queue and internal state.
STDIO Interface
LibXR provides a global STDIO
interface that can be bound to ReadPort
/ WritePort
instances and used with the Printf(...)
function to output debug information.
LibXR::STDIO::write_ = uart_cdc.write_port_;
LibXR::STDIO::Printf("Hello, %d", 123);
Usage Examples
For data size of 0, Write will return success directly, and Read will wait for any data to be available before returning (blocking mode).
// Blocking write to UART, timeout set to 100ms (default is infinite wait)
WriteOperation op_block(sem, 100);
uart.Write("Hello", op_block);
// Asynchronous read with callback
ReadOperation op_cb(callback);
uart.Read(buffer, op_cb);
WritePort::Stream Batch Write Interface
WritePort::Stream
provides a chained batch write capability similar to C++ standard streams, making it suitable for high-throughput, large-packet, or consecutive multi-block data writing scenarios. Its advantages include locking the port resource only once, submitting data in batches, reducing queue pressure and fragmentation, all while keeping usage simple and intuitive.
Key Features
- Stream-style Chained Writing: Supports multiple
<<
operations to batch and concatenate multiple data segments, improving throughput efficiency. - Automatic Batch Submission: Unsubmitted data is automatically committed upon destruction, and you can also call
Commit()
manually at any time.
Example Usage
WriteOperation op;
// Typical batch write using stream interface
{
WritePort::Stream s(&uart_port, op);
s << data1 << data2 << data3;
// s.Commit(); // Optional, auto-committed on destruction
}
Typical Scenarios
- Batch output for UART/serial ports
- Network packet fragmentation, batch logging
- Sending multiple packets at once, greatly reducing write waits and queue contention
Interface Specification
class WritePort::Stream {
public:
Stream(WritePort* port, WriteOperation op); // Locks the port and enters batch write mode
~Stream(); // Destructor automatically commits and releases the lock
Stream& operator<<(const ConstRawData& data); // Appends a data segment
ErrorCode Commit(); // Manually commits the appended data (optional)
};
- Stream(WritePort*, WriteOperation): Attempts to acquire the lock during construction; if locking fails, falls back to normal write mode.
- ~Stream(): Automatically commits all data and releases the lock upon destruction.
- operator<<: Chains the addition of data segments for writing.
- Commit(): Immediately writes all currently appended data to the queue and (if needed) releases the lock. Can be used for segmented flushing.
ReadPort
and WritePort
are the core interfaces of the LibXR I/O abstraction layer. They provide unified data buffering and completion feedback mechanisms, suitable for data stream scenarios such as UART, network, and file systems.