Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 

Repository files navigation

hermes-shm

Hermes carries messages between worlds. This one carries a counter between processes.

A minimal C demo showing how multiple forked worker processes can share a single monotonic counter using anonymous shared memory and C11 atomics.

Origin

This came out of research into secure inter-process communication. The goal was a logging system where worker processes stamp each log entry with a globally unique ID - but without leaving any trace that an outsider could inspect, attach to, or read. Anonymous shared memory turned out to be the right fit: it has no name, no file descriptor visible in /proc, and no presence on disk. It exists only in RAM, only for the lifetime of the master-workers process tree. Nobody outside can see it.

The problem

When a master process forks several workers, each worker runs in its own address space. A counter declared in the parent is copied on fork - each worker gets its own independent copy. Workers cannot agree on a globally unique ID for the things they process.

The solution

Allocate the counter in shared anonymous memory with mmap before forking:

atomic_int *counter = mmap(
    NULL, sizeof(atomic_int),
    PROT_READ | PROT_WRITE,
    MAP_SHARED | MAP_ANONYMOUS,
    -1, 0
);
atomic_init(counter, 0);

MAP_SHARED makes the mapping visible to all forked children. MAP_ANONYMOUS means no backing file - the memory lives only in RAM, inside the master-workers process tree.

Each worker stamps its log entries with a globally unique ID:

int log_id = atomic_fetch_add(counter, 1);

atomic_fetch_add is a single atomic read-modify-write instruction. No mutex, no race condition - every call across every worker returns a distinct value.

Why anonymous memory

  • no file is created on disk
  • not visible in /proc/<pid>/fd like a named shared memory segment would be
  • cannot be opened or attached to by any outside process
  • disappears automatically when all processes that mapped it exit
  • the counter - and anything else stored there - stays entirely inside the process tree, invisible to the rest of the system

Build and run

cc -o counter counter.c
./counter

Example output

[pid=12341 log_id=0  ] user login
[pid=12342 log_id=4  ] user login
[pid=12343 log_id=8  ] user login
[pid=12341 log_id=1  ] file read
...

total log entries stamped: 12

IDs are unique across all workers. Order varies by scheduling.

About

Shared anonymous memory and C11 atomics for unique IDs across worker processes

Topics

Resources

Stars

Watchers

Forks

Contributors

Languages