Magic Ring Buffer

Van C. Ngo · February 1, 2026

A “Magic Ring Buffer” uses virtual memory mirroring to treat a circular buffer as a single, contiguous linear array. This eliminates the need for manual wrap-around logic.

Memory Morroring

To set up the mirrored map, a same physical memory is mapped to two adjacent virtual address regions.

#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>

typedef struct {
    uint8_t *buffer;    // Base virtual address
    size_t size;        // MUST be multiple of page size
    size_t head;        // Write offset
    size_t tail;        // Read offset
} MagicRingBuffer;

// Initialization (Linux/POSIX example)
void init_buffer(MagicRingBuffer *rb, size_t size) {
    int fd = memfd_create("ring_buffer", 0); // Create anonymous file, initially managed by the kernel using physical memory pages RAM
    ftruncate(fd, size);

    // Reserve 2x virtual space
    rb->buffer = mmap(NULL, 2 * size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    
    // Map same physical memory twice, back-to-back
    mmap(rb->buffer, size, PROT_REAuuD|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, 0);
    mmap(rb->buffer + size, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, 0);
    
    rb->size = size;
    rb->head = rb->tail = 0;
    close(fd);
}

Buffer Operations

The code does not need to have wrap-around logic, e.g., avoid the implementation of modulo, because the hardware handles the wrap. This is why the buffer size must be a multiple of the system page size (usually 4KB)

void write_data(MagicRingBuffer *rb, const void *data, size_t len) {
    // Linear copy: If writing past rb->size, it automatically 
    // appears at the start of the first mapping.
    memcpy(rb->buffer + rb->head, data, len);
    rb->head = (rb->head + len) % rb->size;
}

void read_data(MagicRingBuffer *rb, void *dest, size_t len) {
    // Linear read: Even if 'len' crosses the 'size' boundary, 
    // the mirror mapping makes it look contiguous.
    memcpy(dest, rb->buffer + rb->tail, len);
    rb->tail = (rb->tail + len) % rb->size;
}