Shared Memory

Shared memory transport for zero-copy inter-process frame passing.

namespace shmem
class SharedMemRingBuffer
#include <sharedmemringbuffer.h>

Shared memory ring buffer synchronized with POSIX semaphores.

Multi-process ring buffer using multiple SharedMemSegments. Server pushes data, clients pull data with optional timeout. Handles overflow by zeroing semaphore and setting overflow flag.

Usage:

  • Server: Create with is_server=true, use push() to add data

  • Client: Create with is_server=false, use pull() to read data

Synchronization:

  • count_sem: Counts available items for reading

  • overflow_sem: Indicates buffer overflow occurred

// Server process
SharedMemRingBuffer server_ring("my_buffer", 10, 1024, 0, true);
if (!server_ring.init()) {
    // Handle initialization error
    return -1;
}

std::vector<uint8_t> data = {0x01, 0x02, 0x03, 0x04};
if (!server_ring.push(data)) {
    // Handle push error (buffer full, etc.)
}

// Client process  
SharedMemRingBuffer client_ring("my_buffer", 10, 1024, 5000, false); // 5s timeout
if (!client_ring.init()) {
    // Handle initialization error
    return -1;
}

std::vector<uint8_t> received;
if (client_ring.pull(received)) {
    // Process received data
    printf("Received %zu bytes\n", received.size());
} else {
    // Timeout or error occurred
    if (client_ring.isOverflow()) {
        printf("Buffer overflow detected\n");
    }
}
Param name:

Unique identifier for the shared memory buffer

Param n_cells:

Number of ring buffer cells

Param cell_size:

Maximum size per cell in bytes

Param timeout_ms:

Client timeout in milliseconds (0 = no timeout)

Param is_server:

true for server (creates buffer), false for client

Public Functions

SharedMemRingBuffer(const std::string &name, int n_cells, size_t cell_size, int timeout_ms = 0, bool is_server = false)

Constructor.

Parameters:
  • name – Unique identifier for the ring buffer

  • n_cells – Number of cells in the ring buffer

  • cell_size – Maximum size of each cell in bytes

  • timeout_ms – Semaphore timeout in milliseconds (0 = wait forever)

  • is_server – true for server (creates resources), false for client

~SharedMemRingBuffer()

Destructor - cleans up semaphores and segments.

void init()

Initialize the ring buffer.

Must be called after construction. Creates/opens semaphores and segments.

Throws:

std::runtime_error – if initialization fails

void close()

Clean up ring buffer resources.

Must be called before destruction. Closes semaphores and segments.

bool push(const std::vector<uint8_t> &data)

Push data into the ring buffer (server side)

If buffer is full, zeros the semaphore and sets overflow flag.

Parameters:

data – Data to push into the buffer

Throws:

std::runtime_error – if not in server mode or other error

Returns:

true if successful

bool push(const uint8_t *buffer, size_t size)

Push data using direct buffer access (server side)

Zero-copy version for serialized frames.

Parameters:
  • buffer – Pointer to data buffer

  • size – Size of data in bytes

Returns:

true if successful

size_t push(size_t (*frame_serialize_func)(uint8_t*, size_t, Limef::frame::Frame*), Limef::frame::Frame *frame)

Push data using direct buffer access (server side)

Give a frame serialization function that writes directly to the correct shmem buffer Function arguments:

the logic: give a callback function that serializes frame data into the desired memory address (that only the sharedmemringbuffe knows)

Parameters:
  • pointer – to function that takes bytebuffer address and size

  • pointer – to frame

Returns:

returns number of overflown bytes. If all data was written ok, return 0.

bool pull(std::vector<uint8_t> &data)

Pull data from the ring buffer (client side)

Blocks until data is available or timeout occurs.

Parameters:

data – Vector to receive the data

Throws:

std::runtime_error – if not in client mode or other error

Returns:

true if data received, false if timeout

bool pull(const uint8_t *&buffer, size_t &size)

Pull data using direct buffer access (client side)

Zero-copy version for deserialized frames.

Parameters:
  • buffer – Pointer to receive data pointer (read-only)

  • size – Reference to receive data size

Returns:

true if data received, false if timeout

bool isReady() const

Check if ring buffer is ready for use.

Returns:

true if all segments are properly initialized

int getValue() const

Get current semaphore value (available items)

Returns:

int Number of items available for reading

bool isOverflow() const

Check if overflow flag is set.

Returns:

true if buffer overflow occurred

void clearOverflow()

Clear the overflow flag.

void serverUseFd(EventFd &event_fd)

Enable eventfd for server-side signaling (call once after construction)

Registers an eventfd that will be written to (counter += 1) after every successful push(). Call this before the first push().

Parameters:

event_fd – EventFd instance to use for signaling

void clientUseFd(EventFd &event_fd)

Enable eventfd for client-side polling (call once after construction)

Registers the same eventfd so that pull() can drain it when the queue empties. The caller can then use select/poll on the fd to multiplex several ring buffers or other I/O sources.

Parameters:

event_fd – EventFd instance to use for polling

class SharedMemSegment
#include <sharedmemsegment.h>

Simple shared memory segment for serialized frame data.

Manages a POSIX shared memory segment with a size header followed by data. Layout: [size_t data_size][uint8_t data[max_size]]

Usage:

  • Server process: Create with is_server=true, use getWritePtr() + commitWrite()

  • Client process: Create with is_server=false, use getReadPtr() + getDataSize()

Public Functions

SharedMemSegment(const std::string &name, size_t max_size, bool is_server = false)

Constructor.

Parameters:
  • name – Unique identifier for the shared memory segment

  • max_size – Maximum size in bytes for the data payload (not including size header)

  • is_server – true for server (creates shmem), false for client (attaches to existing)

~SharedMemSegment()

Destructor - cleans up shared memory resources.

void init()

Initialize the shared memory segment.

Must be called after construction. For servers, creates and maps the segment. For clients, attempts to attach to existing segment.

Throws:

std::runtime_error – if initialization fails

void close()

Clean up shared memory resources.

Must be called before destruction. Unmaps memory and (for servers) unlinks segment.

uint8_t *getWritePtr()

Get pointer for writing data (server side)

Returns:

uint8_t* Pointer to data area where serialized frame can be written

inline size_t getMaxSize() const

Get maximum available space for data.

Returns:

size_t Maximum bytes that can be written via getWritePtr()

void commitWrite(size_t actual_size)

Commit written data (server side)

Updates the internal size variable to now how much data the current buffer actually has

Parameters:

actual_size – Number of bytes actually written to the buffer

const uint8_t *getReadPtr() const

Get pointer for reading data (client side)

Returns:

const uint8_t* Pointer to data area containing serialized frame

size_t getDataSize() const

Get size of available data (client side)

Returns:

size_t Number of bytes available for reading

bool put(const std::vector<uint8_t> &data)

Copy data into shared memory (server side)

Parameters:

data – Vector containing data to copy

Throws:

std::runtime_error – if data too large or other error

Returns:

true if successful

bool get(std::vector<uint8_t> &data)

Copy data from shared memory (client side)

Parameters:

data – Vector to receive copied data

Returns:

true if successful

inline bool isReady() const

Check if shared memory is ready for use.

Returns:

true if segment is properly initialized and accessible

class ShmemClient
#include <shmem_client.h>

Unified shared memory client — pulls any supported frame type.

Connects to a shared memory ring buffer created by ShmemServerFrameFilter and deserializes frames. The server writes a 1-byte FrameClass tag before every payload; pull() reads that tag and dispatches to the right internal frame object, returning a Frame* base pointer.

Caller downcasts with frame->as<DecodedFrame>() or frame->as<RawFrame>(). The returned pointer is valid until the next pull() call.

Usage:

EventFd event_fd;
ShmemRingbufferContext ctx("myring", 5, 8*1024*1024, 100, event_fd);
ShmemClient client(ctx);

struct pollfd pfd = { event_fd.getFd(), POLLIN, 0 };
while (poll(&pfd, 1, timeout_ms) > 0) {
    Limef::frame::Frame* frame = client.pull();
    if (auto* df = frame->as<Limef::frame::DecodedFrame>()) {
        // decoded video or audio
    } else if (auto* rf = frame->as<Limef::frame::RawFrame>()) {
        // raw bytes
    }
}

Public Functions

Limef::frame::Frame *pull()

Pull next frame from shared memory.

Reads the 1-byte FrameClass tag written by the server, then deserializes the payload into the matching internal frame object.

Returns a pointer to an internal frame that is reused on each call — copy the data if you need it to survive the next pull().

Throws:

std::runtime_error – on timeout, unknown type tag, or deserialization failure

Returns:

Limef::frame::Frame* Pointer to internal DecodedFrame, RawFrame, or StreamFrame

struct ShmemRingbufferContext
#include <sharedmemringbuffer.h>

Context for shared memory communication.

Public Members

std::string ring_name

Name of the shared memory ring buffer.

int ring_size

Number of cells in the ring buffer.

size_t element_size

Maximum size per cell in bytes.

int timeout_ms

Timeout for operations in milliseconds.

Limef::shmem::EventFd &event_fd

EventFd instance for synchronization.