Inter-Process Communication
axeberg provides multiple IPC mechanisms for processes to communicate.
IPC Mechanisms
- Channels: High-level typed message passing
- Pipes: Low-level byte streams
- FIFOs (Named Pipes): Filesystem-visible pipes for unrelated processes
- Message Queues: System V-style tagged message passing
- Shared Memory: Zero-copy data sharing
- Files: Persistent shared state
Channels
Channels are type-safe, MPSC (multiple-producer, single-consumer) queues.
Creating Channels
use axeberg::kernel::channel;
// Create a channel for String messages
let (tx, rx) = channel::<String>();
Sending Messages
// Send a message
tx.send("Hello!".to_string()).unwrap();
tx.send("World!".to_string()).unwrap();
// Clone sender for multiple producers
let tx2 = tx.clone();
tx2.send("From tx2".to_string()).unwrap();
// Close when done sending
tx.close();
Receiving Messages
// Try to receive (non-blocking)
match rx.try_recv() {
Ok(msg) => println!("Got: {}", msg),
Err(TryRecvError::Empty) => println!("No messages"),
Err(TryRecvError::Closed) => println!("Channel closed"),
}
// Async receive - yields until message available
while let Some(msg) = rx.recv().await {
handle(msg);
}
// Loop exits when channel closes
Channel Semantics
- Unbounded: No capacity limit (for now)
- FIFO: Messages delivered in order
- Reference counted: Closes when all senders dropped
- Type-safe: Compile-time type checking
Pipes
Pipes are low-level byte streams.
Creating Pipes
Using Pipes
// Writer
syscall::write(write_fd, b"Hello, pipe!")?;
syscall::close(write_fd)?;
// Reader
let mut buf = [0u8; 100];
let n = syscall::read(read_fd, &mut buf)?;
println!("Read {} bytes", n);
syscall::close(read_fd)?;
Pipe Characteristics
- Unidirectional: One end writes, one reads
- Buffered: 4KB internal buffer
- Reference counted: Shared via
dup() - Blocking: Read blocks when empty (in async)
FIFOs (Named Pipes)
FIFOs are filesystem-visible pipes that allow unrelated processes to communicate.
Creating FIFOs
Using FIFOs
// Writer process
let fd = syscall::open("/tmp/myfifo", OpenFlags::WRITE)?;
syscall::write(fd, b"Hello via FIFO!")?;
syscall::close(fd)?;
// Reader process
let fd = syscall::open("/tmp/myfifo", OpenFlags::READ)?;
let mut buf = [0u8; 100];
let n = syscall::read(fd, &mut buf)?;
syscall::close(fd)?;
FIFO Characteristics
- Named: Appears in filesystem, persists until deleted
- Bidirectional setup: Can open for read or write
- Buffered: 4KB internal buffer (same as pipes)
- Blocking: Opens block until both reader and writer present
Message Queues
System V-style message queues with typed messages for selective receiving.
Creating Message Queues
Sending Messages
// Messages have a type (> 0) and data
syscall::msgsnd(msqid, mtype: 1, b"request data")?;
syscall::msgsnd(msqid, mtype: 2, b"response data")?;
Receiving Messages
// Receive any message (mtype = 0)
let (mtype, data) = syscall::msgrcv(msqid, 0)?;
// Receive specific type only
let (mtype, data) = syscall::msgrcv(msqid, 2)?; // Only type 2
Message Queue Characteristics
- Tagged: Messages have types for selective receiving
- Persistent: Queue persists until explicitly removed
- Bounded: 16KB default capacity
- Priority: Lower message types received first with negative mtype
Shared Memory
For zero-copy data sharing.
Creating Shared Memory
// Process 1: Create segment
let shm_id = syscall::shmget(4096)?;
// Attach and write
let region = syscall::shmat(shm_id, Protection::READ_WRITE)?;
syscall::mem_write(region, 0, b"shared data")?;
syscall::shm_sync(shm_id)?;
Accessing Shared Memory
// Process 2: Attach to existing segment
let region = syscall::shmat(shm_id, Protection::READ)?;
syscall::shm_refresh(shm_id)?;
let mut buf = [0u8; 100];
syscall::mem_read(region, 0, &mut buf)?;
Shared Memory Synchronization
Unlike channels, shared memory requires explicit synchronization:
// Writer
mem_write(region, 0, &new_data)?;
shm_sync(shm_id)?; // Push to shared
// Reader
shm_refresh(shm_id)?; // Pull from shared
mem_read(region, 0, &mut buf)?;
File-Based IPC
Processes can communicate through the filesystem.
// Process 1: Write
let fd = syscall::open("/tmp/ipc", OpenFlags::WRITE)?;
syscall::write(fd, b"message")?;
syscall::close(fd)?;
// Process 2: Read
let fd = syscall::open("/tmp/ipc", OpenFlags::READ)?;
let mut buf = [0u8; 100];
syscall::read(fd, &mut buf)?;
syscall::close(fd)?;
This is simple but not efficient for high-frequency communication.
Choosing an IPC Mechanism
| Mechanism | Best For | Overhead | Type Safety |
|---|---|---|---|
| Channels | Messages, commands | Medium | Yes |
| Pipes | Byte streams, shell pipelines | Low | No |
| FIFOs | Unrelated processes, shell | Low | No |
| Message Queues | Tagged messages, priority | Medium | No |
| Shared Memory | Large data, zero-copy | Very Low | No |
| Files | Persistent state | High | No |
Example: Producer-Consumer
Using channels:
let (tx, rx) = channel::<WorkItem>();
// Producer
kernel::spawn(async move {
for i in 0..100 {
tx.send(WorkItem { id: i, data: vec![0; 1024] }).unwrap();
}
tx.close();
});
// Consumer
kernel::spawn(async move {
loop {
match rx.try_recv() {
Ok(item) => process(item),
Err(TryRecvError::Closed) => break,
Err(TryRecvError::Empty) => futures::pending!(),
}
}
});
Example: Shared Buffer
Using shared memory:
const BUFFER_SIZE: usize = 64 * 1024;
// Create shared buffer
let shm_id = shmget(BUFFER_SIZE)?;
// Writer process
kernel::spawn(async move {
let region = shmat(shm_id, Protection::READ_WRITE)?;
loop {
let data = generate_frame();
mem_write(region, 0, &data)?;
shm_sync(shm_id)?;
futures::pending!();
}
});
// Reader process (e.g., renderer)
kernel::spawn(async move {
let region = shmat(shm_id, Protection::READ)?;
loop {
shm_refresh(shm_id)?;
let mut frame = [0u8; BUFFER_SIZE];
mem_read(region, 0, &mut frame)?;
render(&frame);
futures::pending!();
}
});
Thread Safety Notes
All IPC mechanisms are designed for single-threaded WASM:
- Channels use RefCell internally
- No mutex/lock overhead
- Safe for cooperative multitasking
If multi-threading is added, these would need synchronization primitives.
Related Documentation
- Process Model - Process isolation
- Memory Management - Shared memory details
- Executor - Async task scheduling
- Work Tracker - All work items and planned enhancements