Course contentsShow
← Rust
Lesson 1427 of 1,91012. Unsafe Rust and Low-Level AccessFree lesson

Handling Inter-process Shared Memory

You will map shared memory regions into the current process address space safely.

In this lesson, you will learn how to map an existing shared memory region into your process's address space using safe abstractions over raw pointers.

When multiple processes need to communicate without the overhead of sockets or pipes, they often map the same physical memory pages into their respective virtual address spaces. In Rust, this usually involves interacting with OS primitives like mmap (on Unix) or OpenFileMapping (on Windows).

Once you have a file descriptor or handle representing a shared memory object, your goal is to map that region into your process. This process requires unsafe blocks because the kernel is granting your process access to memory that is managed externally.

Mapping the Region

To map memory, you typically request the OS to assign a pointer to a specific size of the shared object. Since this memory is external, you must treat it as potentially volatile and be hyper-aware of your Pointer Arithmetic and Explicit Pointer Alignment.

use std::ptr::NonNull;

// Imagine 'fd' is a file descriptor for a shared memory object
// We use mmap to get a raw pointer to the start of the region
let size = 4096;
let ptr = unsafe {
    libc::mmap(
        std::ptr::null_mut(),
        size,
        libc::PROT_READ | libc::PROT_WRITE,
        libc::MAP_SHARED,
        fd,
        0,
    )
};

if ptr == libc::MAP_FAILED {
    panic!("Failed to map shared memory");
}

// Map the raw pointer to a slice for safe(r) usage
let shared_data: &mut [u8] = unsafe {
    std::slice::from_raw_parts_mut(ptr as *mut u8, size)
};

Safety Considerations

Even after mapping the memory, you must remain vigilant. Because this memory is shared across processes, another process could modify it at any time. You cannot trust the contents of this memory to remain constant between two consecutive reads.

To bridge this to safe Rust, wrap the pointer in a struct that enforces synchronization. You might use Atomic Operations within the shared region to coordinate access, ensuring that even if the raw memory is external, your process's interaction with it is logically sound. By creating a custom "SharedBuffer" type that implements Drop to unmap the memory, you ensure that you don't leak address space mappings when your object goes out of scope.

Key Takeaway: Mapping shared memory requires using unsafe to bind a pointer to an external file descriptor, necessitating strict use of volatile operations and atomics to manage concurrent access between processes.