blob: 945ea564e6e41b03e129aae9f65f1fef900a871b [file] [log] [blame]
.. _module-pw_multibuf:
===========
pw_multibuf
===========
.. pigweed-module::
:name: pw_multibuf
Sending or receiving messages via RPC, transfer, or sockets often requires a
series of intermediate buffers, each requiring their own copy of the data.
``pw_multibuf`` allows data to be written *once*, eliminating the memory, CPU
and latency overhead of copying.
-----------------
How does it work?
-----------------
``pw_multibuf`` uses several techniques to minimize copying of data:
- **Header and Footer Reservation**: Lower-level components can reserve space
within a buffer for headers and/or footers. This allows headers and footers
to be added to user-provided data without moving users' data.
- **Native Scatter/Gather and Fragmentation Support**: Buffers can refer to
multiple separate chunks of memory. Messages can be built up from
discontiguous allocations, and users' data can be fragmented across multiple
packets.
- **Divisible Memory Regions**: Incoming buffers can be divided without a copy,
allowing incoming data to be freely demultiplexed.
-------------------------------
What kinds of data is this for?
-------------------------------
``pw_multibuf`` is best used in code that wants to read, write, or pass along
data which are one of the following:
- **Large**: ``pw_multibuf`` is designed to allow breaking up data into
multiple chunks. It also supports asynchronous allocation for when there may
not be sufficient space for incoming data.
- **Communications-Oriented**: Data which is being received or sent across
sockets, various packets, or shared-memory protocols can benefit from the
fragmentation, multiplexing, and header/footer-reservation properties of
``pw_multibuf``.
- **Copy-Averse**: ``pw_multibuf`` is structured to allow users to pass around
and mutate buffers without copying or moving data in-memory. This can be
especially useful when working in systems that are latency-sensitive,
need to pass large amounts of data, or when memory usage is constrained.
-------------
API Reference
-------------
Most users of ``pw_multibuf`` will start by allocating a ``MultiBuf`` using
a ``MultiBufAllocator`` class, such as the ``SimpleAllocator``.
``MultiBuf`` s consist of a number of ``Chunk`` s of contiguous memory regions.
``Chunk`` s can be grown or shrunk which allows ``MultiBuf``s to be grown or
shrunk. This allows, for example, lower layers to reserve part of a
``MultiBuf`` for a header or footer (see ``Chunk`` for more details).
``MultiBuf`` exposes an ``std::byte`` iterator interface as well as a ``Chunk``
iterator available through the ``Chunks()`` method. It allows extracting a
``Chunk`` as an RAII-style ``OwnedChunk`` which manages its own lifetime.
.. doxygenclass:: pw::multibuf::Chunk
:members:
.. doxygenclass:: pw::multibuf::OwnedChunk
:members:
.. doxygenclass:: pw::multibuf::MultiBuf
:members:
.. doxygenclass:: pw::multibuf::MultiBufAllocator
:members:
.. doxygenclass:: pw::multibuf::SimpleAllocator
:members:
.. doxygenclass:: pw::multibuf::Stream
:members:
Test-only features
==================
.. doxygenclass:: pw::multibuf::test::SimpleAllocatorForTest
:members:
---------------------------
Allocator Implementors' API
---------------------------
Some users will need to directly implement the ``MultiBufAllocator`` interface
in order to provide allocation out of a particular region, provide particular
allocation policy, fix Chunks to some size (such as MTU size - header for
socket implementations), or specify other custom behavior.
These users will also need to understand and implement the following APIs:
.. doxygenclass:: pw::multibuf::ChunkRegionTracker
:members:
A simple implementation of a ``ChunkRegionTracker`` is provided, called
``HeaderChunkRegionTracker``. It stores its ``Chunk`` and region metadata in a
``Allocator`` allocation alongside the data. The allocation process is
synchronous, making this class suitable for testing. The allocated region or
``Chunk`` must not outlive the provided allocator.
.. doxygenclass:: pw::multibuf::HeaderChunkRegionTracker
:members:
Another ``ChunkRegionTracker`` specialization is the lightweight
``SingleChunkRegionTracker``, which does not rely on ``Allocator`` and uses the
provided memory view to create a single chunk. This is useful when a single
``Chunk`` is sufficient at no extra overhead. However, the user needs to own
the provided memory and know when a new ``Chunk`` can be requested.
.. doxygenclass:: pw::multibuf::SingleChunkRegionTracker
:members: