Operating Systems Laboratory
Capstone Projects & Advanced System Simulations
This document outlines 15 comprehensive capstone projects designed to transition students from theoretical OS concepts to practical, systems-level engineering. These projects synthesize process management, memory allocation, concurrency, and file systems into real-world applications.
Project 1: The “Bank Heist” (Defeating Race Conditions)
Description: Students are provided with a multi-threaded banking application that processes thousands of deposits and withdrawals to a shared bank_balance. The starter code intentionally lacks synchronization. Students must identify the race condition causing money to “vanish” and implement strict POSIX mutex locks or semaphores to secure the transaction pipeline.
Expected Input: A batch parameter specifying the number of concurrent transaction threads (e.g., 10,000).
Expected Output: A terminal log showing the initial balance, active thread executions, and a mathematically perfectly resolved final balance (zero data corruption).
Deliverables:
- The vulnerable C code demonstrating the corrupted final balance.
- The secured C code utilizing
<pthread.h>and<semaphore.h>. - A 1-page analysis explaining the exact assembly-level instruction interleaving that caused the original race condition.
Project 2: The Controlled “Fork Bomb” (Resource Limits & Security)
Description: This project teaches system resource exhaustion and containment. Students will write a program that infinitely spawns child processes using a while(1) { fork(); } loop inside an isolated virtual machine. They will then learn to use Linux ulimit and cgroups to restrict user process limits, effectively neutralizing the bomb.
Expected Input: Execution of the binary before and after applying strict OS-level resource limits.
Expected Output: System crash/freeze (Phase 1). A graceful failure where the OS intercepts and blocks process creation, outputting Resource temporarily unavailable (Phase 2).
Deliverables:
- The C source code for the fork bomb.
- A step-by-step terminal script documenting the
ulimitcommands used to secure the user environment.
Project 3: Building a Custom “Mini-Shell”
Description: Students will build their own Command Line Interface (CLI) in C. The shell must parse user input, use fork() to spawn child processes, and use the execvp() family to execute standard Linux commands (like ls, pwd, or cat). It must also implement the wait() system call to prevent the shell from accepting new input until the foreground process finishes.
Expected Input: Standard bash commands typed into the custom StudentOS> prompt.
Expected Output: The accurate execution and terminal output of the requested commands, identical to a native Linux bash environment.
Deliverables:
- The C source code implementing the infinite read-eval-print loop (REPL).
- Advanced implementation: Support for background process execution using the
&operator.
Project 4: Edge Node Load Balancer (CPU Scheduling in Dense Networks)
Description: Applying CPU scheduling to distributed systems. Students simulate an edge computing node receiving thousands of heterogeneous data requests (e.g., lightweight sensor telemetry vs. heavy video processing). They must implement a Priority or Shortest Job First (SJF) algorithm to efficiently clear the local queue and prevent bottlenecking before forwarding tasks to the cloud. Expected Input: A large CSV file containing 10,000 simulated process requests (Arrival Time, Burst Time, Task Type). Expected Output: A processed log detailing the execution order, along with aggregate statistics for Average Waiting Time and Turnaround Time. Deliverables:
- The C source code for the edge load balancer.
- A performance graph comparing their SJF/Priority implementation against a baseline First-Come, First-Served (FCFS) approach.
Project 5: Docker’s Roots: Namespaces and Process Isolation
Description: Modern containerization relies heavily on OS primitives. Students will use the Linux clone() system call with the CLONE_NEWPID flag to create a child process that has its own isolated PID namespace. The child will believe it is PID 1 (the init process), demonstrating how tools like Docker isolate applications from the host OS.
Expected Input: Execution of the custom C binary with elevated (root) privileges.
Expected Output: The parent process prints its PID (e.g., 4056). The child process prints its PID, which will output as 1, successfully proving namespace isolation.
Deliverables:
- The C source code utilizing
sched.hand namespace flags. - A brief report connecting this mechanism to modern cloud-native container architecture.
Project 6: User-Space Memory Allocator (malloc and free clone)
Description: Students bypass the standard C library memory allocation and request a large block of raw memory from the OS kernel using the sbrk() or mmap() system calls. They must then write their own versions of malloc() and free() to manage this block using a linked list and a First-Fit or Best-Fit contiguous allocation strategy.
Expected Input: Various internal calls to custom_malloc(size) and custom_free(pointer) within a test program.
Expected Output: Successful allocation and deallocation of memory addresses, with no memory leaks or segmentation faults.
Deliverables:
- A header file (
custom_mem.h) and implementation file containing the allocator. - A test suite proving the allocator correctly handles memory fragmentation.
Project 7: Competitive Algorithm Leaderboard (Disk Scheduling)
Description: A class-wide optimization challenge. Students are provided a massive hidden dataset of randomized magnetic disk track requests. They must implement the most highly optimized C-SCAN (Circular SCAN) or SSTF (Shortest Seek Time First) algorithm possible to minimize total head movement. Expected Input: A unified dataset of 50,000 disk I/O requests. Expected Output: The absolute minimum number of total head movements (seek distance) calculated by the algorithm. Deliverables:
- The optimized C source code.
- The algorithm will be run against a hidden evaluation dataset to rank the most efficient code on the laboratory leaderboard.
Project 8: Asynchronous Chat Application (Advanced IPC)
Description: Using POSIX Message Queues, students will build a two-way, asynchronous command-line chat application. Two independent terminal windows will run the client binaries. The system must use msgget(), msgsnd(), and msgrcv() to allow real-time communication, utilizing message types to differentiate between standard messages and “typing…” status indicators.
Expected Input: Text strings typed into Terminal A and Terminal B.
Expected Output: Real-time appearance of the text in the opposite terminal, managed entirely through kernel-level IPC queues rather than network sockets.
Deliverables:
chat_client.csource code.- Proper queue destruction logic (
msgctlwithIPC_RMID) upon exiting the application to prevent kernel memory pollution.
Project 9: Distributed Deadlock Detection Engine
Description: Extending the Banker’s Algorithm. Instead of a single system, students simulate a distributed database cluster where multiple nodes hold and request locks on shared tables. The program must periodically scan a central allocation matrix, build a Resource Allocation Graph (RAG), and detect cycle formations (deadlocks) in real-time.
Expected Input: A dynamic stream of lock requests and lock releases from various simulated nodes.
Expected Output: Real-time log granting requests, until a cycle is formed, at which point the system outputs DEADLOCK DETECTED: Nodes [X, Y, Z] involved in circular wait.
Deliverables:
- C source code implementing the cycle-detection algorithm.
- A test script that intentionally forces a circular wait to prove the detection engine works.
Project 10: File System Defragmenter Simulation
Description: Taking contiguous memory allocation further, students simulate a heavily fragmented hard drive. They will be given an array representing disk blocks, with files scattered chaotically due to simulated deletions and creations. They must write a compaction algorithm that shifts all active file blocks to one end of the array, updating the simulated directory pointers, to create a single massive free block.
Expected Input: An array representing a fragmented disk (e.g., [FileA, FileA, FREE, FileB, FREE, FREE, FileC]).
Expected Output: A compacted array (e.g., [FileA, FileA, FileB, FileC, FREE, FREE, FREE]) and an updated directory table showing the new starting block for each file.
Deliverables:
- The C source code for the defragmentation engine.
- A before-and-after memory map printed to the terminal.
Project 11: The Thrashing Simulator (Page Replacement)
Description: A stress-test of virtual memory concepts. Students simulate a system with a very small physical frame count (e.g., 4 frames) but a massively demanding logical reference string representing three concurrent applications. They will run this simulation through both FIFO and LRU algorithms to empirically demonstrate “thrashing” (where page fault rates near 100%). Expected Input: A highly volatile array of page references and a severely restricted frame constraint. Expected Output: A terminal graph or tabular output showing the page fault rate skyrocketing as the reference string is processed. Deliverables:
- The C simulation code.
- An analytical summary explaining how increasing the locality of reference in the application code could prevent the thrashing observed in the simulation.
Project 12: Multi-Threaded Web Server
Description: Combining OS process concepts with networking. Students will write a basic HTTP web server in C using <sys/socket.h>. To handle multiple simultaneous browser requests, the server must implement a thread pool using <pthread.h>. When a connection arrives, the main thread dispatches it to a worker thread for processing.
Expected Input: Standard HTTP GET requests sent from a web browser to localhost:8080.
Expected Output: The browser successfully rendering an HTML page served by the C program.
Deliverables:
- The C source code for the server.
- Proof of concurrency: A stress-test demonstrating the server handling 50 simultaneous browser connections without dropping packets.
Project 13: In-Memory Key-Value Store (Readers-Writers Problem)
Description: Students will build a high-speed, in-memory database (similar to a basic Redis clone) structured around a Hash Table. The challenge is concurrency: multiple threads will attempt to read and write to the database simultaneously. Students must implement the classical Readers-Writers synchronization solution, allowing multiple concurrent readers, but strictly isolated, exclusive access for writers.
Expected Input: Concurrent threads issuing PUT(key, value) and GET(key) commands.
Expected Output: Accurate data retrieval with zero race conditions, prioritizing read-heavy throughput.
Deliverables:
- The C source code for the Key-Value store and threading logic.
- A performance metric showing the time taken to process 10,000 reads and 1,000 writes.
Project 14: Designing a Micro-File System
Description: Students build a functional, miniature file system entirely inside a single 10MB binary file on their hard drive. They must format this 10MB file by defining a Superblock (for volume metadata), an Inode table (for file metadata/pointers), and Data blocks. They will write an interface to copy_in, copy_out, and list files inside their virtual disk.
Expected Input: Commands like ./myfs format, ./myfs copy_in test.txt, and ./myfs list.
Expected Output: The successful storage and retrieval of real text files in and out of their 10MB binary “disk”.
Deliverables:
- The C source code implementing the Superblock, Inode, and Data block read/write logic.
- A hex dump (
xxd) of the 10MB file proving the data was written correctly at the byte level.
Project 15: Network Packet Logger & Graceful Shutdown (Signal Handling)
Description: Synthesizing signal trapping and I/O. Students write a program that opens a raw socket to continuously sniff and log incoming network packets to a text file. The primary challenge is data integrity: if the user presses Ctrl-C, the program must trap the SIGINT signal, stop accepting new packets, explicitly flush the I/O buffers, safely close the file pointers, and then exit gracefully without corrupting the log.
Expected Input: Continuous network traffic, interrupted suddenly by a keyboard signal (SIGINT).
Expected Output: A perfectly formatted packet log file that cuts off cleanly exactly when the signal was received, with no corrupted or half-written binary data at the end of the file.
Deliverables:
- The C source code featuring the custom signal handler and I/O flushing logic.