Skip to content

Instantly share code, notes, and snippets.

@zeusdeux
Last active January 19, 2026 19:02
Show Gist options
  • Select an option

  • Save zeusdeux/1d13f1516c9c345195f92e8ffb971e2c to your computer and use it in GitHub Desktop.

Select an option

Save zeusdeux/1d13f1516c9c345195f92e8ffb971e2c to your computer and use it in GitHub Desktop.
mmap same underlying memory twice into a virtual address space of twice the underlying memory size for use as a circular buffer/ring buffer
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
typedef enum {
L_ERROR = 0,
L_WARN,
L_INFO,
L_COUNT,
} LOG_LEVEL;
static const char *LOG_LEVEL_STR[L_COUNT] = {
"ERROR",
"WARN",
"INFO"
};
#define log(level, ...) do { \
fprintf(stderr, "%s:%d: ", __FILE__, __LINE__); \
fprintf(stderr, "[%s] ", LOG_LEVEL_STR[(level)]); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
} while(0)
#define bail(...) do { \
fprintf(stderr, "%s:%d:\t[%s] ", __FILE__, __LINE__, __func__); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
exit(EXIT_FAILURE); \
} while(0)
#define fuckoff(f) do { \
if (fclose((f)) < 0) { \
bail("Failed to close temp file due to %s", strerror(errno)); \
} \
} while(0)
#define fuckoffmore(ptr, sz) do { \
if ((ptr) != NULL) { \
if (munmap((ptr), (sz)) < 0) { \
bail("Failed to munmap %p of size %zu bytes", (void *)(ptr), (sz)); \
} \
} \
} while(0)
// gcc -std=c17 -Wall -Wextra -Wdeprecated -Wpedantic -pedantic -g -DDEBUG -o mmap-circular-buffer mmap-circular-buffer.c && ./mmap-circular-buffer
int main(void)
{
long page_size = sysconf(_SC_PAGESIZE);
FILE *tmp_file = tmpfile();
log(L_INFO, "System page size: %ld bytes", page_size);
if (tmp_file == NULL) {
fuckoff(tmp_file);
bail("Failed to open temp file due to %s", strerror(errno));
}
/* int fd = shm_open(circular_buffer_file_name, O_RDWR | O_CREAT | O_EXCL, 0666); // this shit doesn't work on macos */
int fd = fileno(tmp_file);
size_t n = page_size / sizeof(size_t);
size_t sz = n * sizeof(size_t);
log(L_INFO, "Number of elements in circular buffer: %zu (%zu bytes)", n, sz);
if (ftruncate(fd, sz) < 0) {
fuckoff(tmp_file);
bail("ftruncate failed on fd %d due to %s", fd, strerror(errno));
}
log(L_INFO, "Truncated temp file to %zu bytes", sz);
size_t circular_buffer_sz = sz * 2;
size_t *circular_buffer = mmap(NULL, circular_buffer_sz, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (circular_buffer == MAP_FAILED) {
fuckoff(tmp_file);
fuckoffmore(circular_buffer, circular_buffer_sz);
bail("mmap of circular buffer failed due to %s", strerror(errno));
}
log(L_INFO, "Got %zu bytes of virtual address space starting at %p", circular_buffer_sz, (void *)circular_buffer);
size_t region_sz = sz;
size_t *first = mmap(circular_buffer, region_sz, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd, 0);
if (first == MAP_FAILED) {
fuckoff(tmp_file);
fuckoffmore(first, region_sz);
fuckoffmore(circular_buffer, circular_buffer_sz);
bail("mmap of first region of circular buffer failed due to %s", strerror(errno));
}
log(L_INFO, "Mapped first half of circular buffer (starting = %p, size = %zu bytes) to backing temp file ", (void *)first, region_sz);
size_t *second = mmap((void *)((ptrdiff_t)circular_buffer + region_sz), region_sz , PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd, 0);
if (second == MAP_FAILED) {
fuckoff(tmp_file);
fuckoffmore(first, region_sz);
fuckoffmore(second, region_sz);
fuckoffmore(circular_buffer, circular_buffer_sz);
bail("mmap of second region of circular buffer failed due to %s", strerror(errno));
}
log(L_INFO, "Mapped second half of circular buffer (starting = %p, size = %zu bytes) to the SAME backing temp file ", (void *)second, region_sz);
log(L_INFO, "------------------------------------------------------------");
circular_buffer[0] = 123;
log(L_INFO, "set circular_buffer[%4d]: %d", 0, 123);
circular_buffer[2047] = 456;
log(L_INFO, "set circular_buffer[%d]: %d", 2047, 456);
log(L_INFO, "------------------------------------------------------------");
log(L_INFO, "get circular_buffer[%4d]: %zu", 0, circular_buffer[0]);
log(L_INFO, "get circular_buffer[%d]: %zu", 2047, circular_buffer[2047]);
log(L_INFO, "------------------------------------------------------------");
log(L_INFO, "Access beyond 2048 elements wraps around as shown below");
log(L_INFO, "get circular_buffer[%d]: %zu", 2048, circular_buffer[2048]);
log(L_INFO, "get circular_buffer[%d]: %zu", 4095, circular_buffer[4095]);
log(L_INFO, "------------------------------------------------------------");
fuckoff(tmp_file);
fuckoffmore(first, region_sz);
fuckoffmore(second, region_sz);
fuckoffmore(circular_buffer, circular_buffer_sz);
log(L_INFO, "Cleaned up all resources");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment