This project implements Conway's Game of Life using a multi-process architecture with Inter-Process Communication (IPC).
┌─────────────────────────────────────────────────────────────┐
│ Browser (Angular) │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Draw Canvas │ │ Simulation View │ │
│ │ (Left Panel) │ │ (Right Panel) │ │
│ └──────────────────┘ └──────────────────┘ │
│ │ │ │
│ └────────────┬──────────────────────┘ │
│ │ HTTP REST API │
└────────────────────────┼─────────────────────────────────────┘
│
▼
┌────────────────────────┐
│ HTTP Server (C) │
│ Port 8081 │
└────────────┬───────────┘
│
▼
┌────────────────────────┐
│ Grid Manager (C) │
│ - fork() cells │
│ - coordinate IPC │
└────────────┬───────────┘
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Cell[0,0]│ │Cell[0,1]│ ... │Cell[n,n]│
│ Process │ │ Process │ │ Process │
│ (fork) │ │ (fork) │ │ (fork) │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
│ pipe() │ pipe() │
└────────────────┴───────────────┘
Bidirectional Communication
DrawCanvasComponent
- Interactive drawing canvas
- 20x20 grid for pattern creation
- Click and drag to draw
- Toggle between draw/erase modes
SimulationViewComponent
- Displays live simulation
- Shows generation count
- Displays number of alive cells
- Highlights all processes (alive and dead)
ConwayService
- HTTP client for API communication
- Handles state queries, cell updates, and ticks
- Provides auto-tick observable for animation
AppComponent
- Main orchestration component
- Controls simulation start/stop/step/reset
- Manages timing and coordination
cell.c / cell.h
- Cell process implementation
- Runs in its own forked process
- Maintains cell state (alive/dead)
- Handles IPC messages
- Implements Conway's rules
grid.c / grid.h
- Grid manager
- Spawns cell processes using
fork() - Creates pipe pairs for each cell
- Coordinates generation ticks
- Collects and distributes cell states
server.c / server.h
- HTTP REST API server
- Socket-based implementation
- Handles GET/POST requests
- CORS support for Angular dev server
main.c
- Entry point
- Signal handling (SIGINT/SIGTERM)
- Cleanup and graceful shutdown
Each cell process has two pipes:
Parent Process Child Process (Cell)
│ │
│ ┌──────────────────────────┐ │
├──┤ pipe[1] (write_fd) ├─────────┤── pipe[0] (read_fd)
│ └──────────────────────────┘ │
│ Commands (MSG_*) │
│ │
│ ┌──────────────────────────┐ │
├──┤ pipe[0] (read_fd) ├─────────┤── pipe[1] (write_fd)
│ └──────────────────────────┘ │
│ Responses (state) │
typedef enum {
MSG_STATE_QUERY, // Query cell's current state
MSG_STATE_RESPONSE, // Response with state
MSG_UPDATE, // Update cell's state
MSG_TICK, // Compute next generation
MSG_SHUTDOWN // Terminate process
} MessageType;Initialization:
- Parent forks a child process for each cell
- Parent keeps write_fd for commands
- Child keeps read_fd for receiving commands
- Bidirectional communication established
State Update:
Browser → HTTP → Grid Manager → pipe → Cell Process
↓
Updates state
Generation Tick:
Browser → HTTP → Grid Manager
↓
Broadcast MSG_TICK to all cells
↓
Each cell queries neighbors
↓
Each cell computes next state
↓
Cells respond with new state
↓
Grid Manager collects responses
↓
Grid Manager updates all cells
↓
HTTP Response → Browser
Implemented in cell_compute_next_state():
- Survival: Live cell with 2-3 neighbors → stays alive
- Birth: Dead cell with exactly 3 neighbors → becomes alive
- Death: All other cases → cell dies or stays dead
if (cell_is_alive) {
return (neighbors == 2 || neighbors == 3);
} else {
return (neighbors == 3);
}Returns current grid state:
{
"width": 20,
"height": 20,
"generation": 42,
"cells": [
{"x": 5, "y": 5},
{"x": 5, "y": 6}
]
}Set individual cell state:
{
"x": 10,
"y": 10,
"alive": 1
}Advance one generation. Returns:
{
"success": true,
"generation": 43
}Clear all cells:
{
"success": true
}- Processes: 400 (1 per cell)
- File Descriptors: 800 (2 pipes per cell)
- Memory: ~1-2MB per process = ~400-800MB total
- Generation Time: O(n²) where n = grid dimension
- Limited by system's process/fd limits
- Default max: 50x50 (2500 processes)
- Can be adjusted in
grid.h:#define MAX_GRID_SIZE 50
makeormake all- Build the projectmake clean- Remove build artifactsmake run- Build and run servermake debug- Build with debug symbols
-Wall -Wextra- All warnings-O2- Optimization level 2-Iinclude- Include header directory-lpthread- Link pthread (for future extensions)
- No input validation: This is a demo project
- CORS wide open: Allows all origins
- No authentication: Public API
- Resource limits: Can spawn many processes
Note: This is a demonstration project. Production use would require proper input validation, authentication, and resource limits.
- Direct cell-to-cell IPC: Use SCM_RIGHTS to pass FDs between processes
- WebSocket support: Real-time updates instead of polling
- Shared memory: For faster state synchronization
- Thread pool: Alternative to process-per-cell
- Pattern library: Pre-defined patterns (glider, blinker, etc.)
- Grid resizing: Dynamic grid size changes
- Performance metrics: Process stats, IPC latency