A simulated operating system kernel built in C++ using object oriented priciples , modeling how a real OS schedules
processes, manages memory through paging, and arbitrates access to I/O devices —
implemented as a clean, extensible class hierarchy rather than a single procedural
main().
Kernel
/ | \
ProcessManager MemoryManager IOManager
| | |
Scheduler Pager DeviceManager
|
FCFS SJF RR Priority MLFQ
g++ -std=c++17 -Iinclude -Wall src/*.cpp main.cpp -o os_simulator
./os_simulatorTop-level owner of the three subsystems below. Doesn't contain logic itself
— it composes ProcessManager, MemoryManager, and IOManager and exposes
a simple interface (boot(), runProcessScheduling(), printAllReports())
so main.cpp doesn't need to know the internal wiring.
Processis the PCB (Process Control Block) — PID, state, arrival time, burst time, remaining time, priority, and MLFQ queue level.Scheduleris an abstract base class exposingpickNext()andtimeSlice(). Five concrete strategies implement it:FCFSScheduler,SJFScheduler,RRScheduler,PriorityScheduler,MLFQScheduler.ProcessManagerholds aScheduler*, not a concrete scheduler type. It runs a time-driven simulation loop: admit arrivals → ask the scheduler who runs next → simulate a context switch → advance time → check completion or requeue. It has zero knowledge of which algorithm is plugged in.
MemoryManagerowns a fixed pool of physical frames and tracks which are free/occupied.Pageris a per-process page table, mapping logical pages to physical frames. Each process gets its ownPagerinstance.allocate()/deallocate()simulate a process acquiring and releasing memory, with a free-frame count that visibly shrinks and recovers.
DeviceManagertracks named devices (e.g. Disk, Printer) and which PID currently owns each one.IOManagerqueues incoming I/O requests and services them one at a time, re-queuing a request if the requested device is busy — a simplified model of blocking I/O and device contention.
The program runs the same 4-process workload (P1–P4, arriving at times 0/1/2/3 with bursts of 8/4/9/5) through all five schedulers back-to-back, then runs a separate Kernel integration demo combining scheduling, memory allocation, and I/O device contention.
--- FCFS Scheduling Report ---
PID Name Arrival Burst Completion Waiting Turnaround
1 P1 0 8 8 0 8
2 P2 1 4 12 7 11
3 P3 2 9 21 10 19
4 P4 3 5 26 18 23
Average Waiting Time: 8.75
Average Turnaround Time: 15.25
Context Switches: 4
--- SJF Scheduling Report ---
PID Name Arrival Burst Completion Waiting Turnaround
1 P1 0 8 8 0 8
2 P2 1 4 12 7 11
3 P3 2 9 26 15 24
4 P4 3 5 17 9 14
Average Waiting Time: 7.75
Average Turnaround Time: 14.25
Context Switches: 4
--- Round Robin Scheduling Report --- (quantum = 3)
PID Name Arrival Burst Completion Waiting Turnaround
1 P1 0 8 23 15 23
2 P2 1 4 16 11 15
3 P3 2 9 26 15 24
4 P4 3 5 21 13 18
Average Waiting Time: 13.5
Average Turnaround Time: 20
Context Switches: 10
--- Priority Scheduling Report ---
PID Name Arrival Burst Completion Waiting Turnaround
1 P1 0 8 8 0 8
2 P2 1 4 17 12 16
3 P3 2 9 26 15 24
4 P4 3 5 13 5 10
Average Waiting Time: 8
Average Turnaround Time: 14.5
Context Switches: 4
--- MLFQ Scheduling Report --- (levels: quantum 2, 4, 8)
PID Name Arrival Burst Completion Waiting Turnaround
1 P1 0 8 23 15 23
2 P2 1 4 14 9 13
3 P3 2 9 26 15 24
4 P4 3 5 21 13 18
Average Waiting Time: 13
Average Turnaround Time: 19.5
Context Switches: 10
========== Kernel Integration Demo ==========
========================================
Simulated Kernel Booting...
========================================
[IOManager] PID 1 requested Disk
[IOManager] PID 2 requested Disk
[DeviceManager] Disk granted to PID 1
[DeviceManager] Disk busy (held by PID 1), PID 2 must wait
--- Round Robin Scheduling Report ---
PID Name Arrival Burst Completion Waiting Turnaround
1 P1 0 8 23 15 23
2 P2 1 4 16 11 15
3 P3 2 9 26 15 24
4 P4 3 5 21 13 18
Average Waiting Time: 13.5
Average Turnaround Time: 20
Context Switches: 10
[MemoryManager] Frames: XXXXXXXXXXX..... (5/16 free)
[DeviceManager] Status: Printer=free Disk=PID1
[MemoryManager] Frames: ................ (16/16 free)
- SJF gives the lowest average waiting time (7.75) of all five — expected, since SJF is provably optimal for minimizing average waiting time when all processes are available together, at the cost of potentially starving longer jobs.
- FCFS and SJF and Priority all show only 4 context switches — each is non-preemptive here, so once a process starts running it runs to completion, one switch per process.
- RR and MLFQ show 10 context switches — both are preemptive (fixed quantum for RR, per-level quantum for MLFQ), so long processes get interrupted and resumed multiple times. This is the classic fairness vs. overhead tradeoff: RR/MLFQ are more responsive to short jobs but pay for it in extra context-switch overhead and slightly higher average waiting time (13.5 and 13) compared to FCFS/SJF/Priority.
- The Kernel Integration Demo shows all three subsystems interacting:
memory is allocated per-process before scheduling starts (frame count
drops from 16 free to 5 free as P1–P4 claim 3+2+4+2 = 11 frames), the
IOManagergrants the Disk to PID 1 and correctly queues PID 2's request since the device is busy (mutual exclusion in action), and after scheduling completes, memory is deallocated and all 16 frames return to free — confirming no memory leaks in the simulation itself.
os-simulator/
├── include/ # class headers
├── src/ # implementations
├── main.cpp # demo workload + kernel integration demo
└── README.md