← All virtual labs
Operating Systems · Virtual lab

Scheduling, paging, deadlock & concurrency

Six self-contained experiments, each a genuinely computing simulator written in plain JavaScript — no libraries. Every algorithm runs over data you type: edit the process table, the reference string, the request queue or the allocation matrices and watch the Gantt chart, frame grid, head-movement plot, safe sequence and semaphore state machine recompute exactly. Move through Aim, Theory, Procedure, the live Simulation, a graded Self-assessment and References.

1 · CPU scheduling

FCFS, SJF, SRTF, Round-Robin and Priority — Gantt chart, waiting and turnaround time
To schedule a set of processes — each with an arrival time and a CPU burst — under five classic policies, to draw the resulting Gantt chart, and to compute and compare the average waiting time and average turnaround time each policy produces.

A CPU scheduler picks, at every decision point, which ready process runs next on the single CPU. FCFS (first-come-first-served) runs processes in arrival order and is non-preemptive. SJF (shortest-job-first, non-preemptive) always picks the ready process with the smallest total burst; it is provably optimal for minimum average waiting time when all jobs are present. SRTF is preemptive SJF: at every tick it runs the process with the smallest remaining time, so an arriving short job can preempt a longer running one. Round-Robin gives each ready process a fixed time quantum in a circular queue — fair and responsive but with more context switches. Priority scheduling runs the highest-priority ready process (here a smaller number means higher priority).

For each process define completion time C, turnaround time and waiting time:

Turnaround TAT = Completion C − Arrival AT
Waiting WT = Turnaround TAT − Burst BT
Response RT = (first CPU time) − Arrival AT
Average WT = (sum of WT) / n    Average TAT = (sum of TAT) / n

FCFS suffers the convoy effect — one long job delays many short ones. SRTF minimises average waiting time but can starve long jobs; Round-Robin trades a little throughput for bounded response time, governed entirely by the quantum.

  1. Open the Simulation tab. A four-process table is preloaded with arrival, burst and priority.
  2. Edit any cell, or press Add / Remove to change the process set, or Randomise for a fresh case.
  3. Choose a policy. For Round-Robin set the time quantum; for Priority recall that a smaller number is higher priority.
  4. Press Run. Read the Gantt chart — each block is a CPU run with start and end times marked.
  5. Read the per-process table of completion, turnaround and waiting times, and the averages at the bottom.
  6. Switch policies on the same data and compare the average waiting time — SJF / SRTF should win.

Gantt chart & results

Per-process results
Avg waiting time
--
Avg turnaround
--
Avg response
--
CPU utilisation
--

Process table

PIDArrivalBurstPrio
RR only
  • Silberschatz, Galvin & Gagne — Operating System Concepts, 10th ed., Ch. 5 (CPU Scheduling). Wiley.
  • Tanenbaum & Bos — Modern Operating Systems, 4th ed., Sec. 2.4. Pearson.
  • Virtual Labs (IIT) — Operating Systems: CPU Scheduling, cse02.vlabs.ac.in.

2 · Page replacement

FIFO, LRU and Optimal — animate the frames, count page faults and the hit ratio
To run a page-reference string through a fixed set of physical frames under three replacement policies, to watch each reference cause a hit or a fault, and to compute the total page faults and the hit ratio for FIFO, LRU and the optimal (Belady) algorithm.

Under demand paging only the pages actually referenced are loaded. When a referenced page is not resident a page fault occurs and, if every frame is full, the policy must evict a victim. FIFO evicts the page that has been resident longest. LRU (least-recently-used) evicts the page whose last use is furthest in the past — it exploits temporal locality. Optimal (Belady's MIN) evicts the page whose next use is furthest in the future; it is unrealisable online but gives the theoretical lower bound on faults.

Hit ratio = hits / total references
Fault ratio = faults / total references = 1 − hit ratio

More frames usually means fewer faults, but FIFO can exhibit Belady's anomaly — adding a frame occasionally increases faults. LRU and Optimal are stack algorithms and never suffer the anomaly. The optimal count is always a lower bound; comparing FIFO and LRU against it measures how good a practical policy is.

  1. Open the Simulation tab. A reference string and a frame count are preloaded.
  2. Edit the reference string (space- or comma-separated page numbers) and set the number of frames.
  3. Pick a policy and press Step to advance one reference at a time, or Run to animate the whole string.
  4. Each column is one reference; green frames mark a hit, amber a fault, and the evicted page is shown.
  5. Read the running faults, hits and hit ratio. Re-run under each policy and against Optimal.

Frame timeline FIFO

Green column = hit, amber = fault. The cell that changes is the page just loaded; the evicted page is noted below it.
Page faults
0
Hits
0
Hit ratio
--
References
0

Configuration

3
6x
  • Silberschatz, Galvin & Gagne — Operating System Concepts, 10th ed., Ch. 10 (Virtual Memory). Wiley.
  • Belady, L. A. — A study of replacement algorithms for a virtual-storage computer. IBM Systems Journal, 1966.
  • Virtual Labs (IIT) — Operating Systems: Page Replacement, cse02.vlabs.ac.in.

3 · Disk scheduling

FCFS, SSTF, SCAN, C-SCAN and LOOK — head-movement plot and total seek distance
To service a queue of disk-cylinder requests from a given head position under five disk-scheduling policies, to draw the head's movement across the platter as a function of service order, and to compute the total head movement (seek distance) each policy incurs.

The dominant cost of a disk access is the seek time — the time to move the read/write head to the target cylinder — which is roughly proportional to the number of cylinders crossed. A disk scheduler reorders the pending request queue to shrink total head movement. FCFS services requests in arrival order (fair, but the head may swing wildly). SSTF (shortest-seek-time-first) always serves the nearest pending request; it is greedy and can starve far requests. SCAN (the elevator) sweeps in one direction to the disk edge, then reverses. C-SCAN sweeps one way, then jumps back to the start and sweeps again, giving more uniform wait. LOOK / C-LOOK behave like SCAN / C-SCAN but turn around at the last request instead of the physical edge.

Total head movement = sum over the service order of |c[i+1] − c[i]|
(starting from the initial head position; C-SCAN counts the wrap-around jump)

SSTF and the elevator family dramatically cut average seek distance versus FCFS under load. C-SCAN sacrifices a little total movement for a more uniform response time, since every cylinder is visited on a regular cycle.

  1. Open the Simulation tab. A request queue, head position and disk size are preloaded.
  2. Edit the request queue (cylinder numbers), the initial head position and the maximum cylinder.
  3. For the elevator policies choose the initial sweep direction (towards 0 or towards the maximum).
  4. Pick a policy and press Run. The plot draws the head's path; each visited cylinder is a turning point.
  5. Read the total head movement and the service order. Compare policies on the same queue.

Head movement FCFS

Service order: --
Total head movement
--
Requests served
0
Avg seek / request
--
Head start
--

Configuration

Up (to max)
Down (to 0)
  • Silberschatz, Galvin & Gagne — Operating System Concepts, 10th ed., Ch. 11 (Mass-Storage Structure). Wiley.
  • Stallings, W. — Operating Systems: Internals and Design Principles, Sec. 11.5. Pearson.
  • Virtual Labs (IIT) — Operating Systems: Disk Scheduling, cse02.vlabs.ac.in.

4 · Deadlock avoidance — Banker's algorithm

Allocation, Max and Available matrices — compute a safe sequence or report unsafe
To run Dijkstra's Banker's algorithm on a system of processes and resource types: to compute the Need matrix, to find a safe execution sequence if one exists, and otherwise to report the state as unsafe — and to test whether a specific resource request can be safely granted.

The Banker's algorithm avoids deadlock by never entering an unsafe state. Each process declares its Max demand of every resource type up front. The system tracks the Allocation already given and the Available (free) units. The remaining demand is the Need:

Need[i][j] = Max[i][j] − Allocation[i][j]

A state is safe if there exists an ordering of all processes such that each can obtain its full Need from the currently free units plus whatever earlier processes release on finishing. The safety check maintains a Work vector (initially Available) and a Finish flag per process; it repeatedly finds an unfinished process whose Need is ≤ Work, simulates it running and releasing, adding its Allocation back to Work:

find i with Finish[i] = false and Need[i] ≤ Work
Work = Work + Allocation[i]; Finish[i] = true; repeat
safe if every Finish[i] becomes true

To check a request by process i, the algorithm tentatively grants it (only if Request ≤ Need and Request ≤ Available), then re-runs the safety check; the request is granted only if the resulting state is still safe.

  1. Open the Simulation tab. A classic 5-process, 3-resource safe state is preloaded.
  2. Set the number of processes and resource types, then edit the Allocation, Max and Available cells. The Need matrix updates live.
  3. Press Check safety. If safe, the safe sequence is shown; if not, the state is reported unsafe.
  4. Enter a resource request for a chosen process and press Test request to see whether granting it keeps the system safe.
  5. Use Load unsafe to see a state with no safe sequence, and Reset for the textbook example.

Matrices

Allocation

Max

Need = Max − Allocation

Available (free units)

Press Check safety to evaluate the current state.

Controls

Test a request

  • Dijkstra, E. W. — EWD108: Een algorithme ter voorkoming van de dodelijke omarming (the Banker's algorithm), 1965.
  • Silberschatz, Galvin & Gagne — Operating System Concepts, 10th ed., Ch. 8 (Deadlocks). Wiley.
  • Virtual Labs (IIT) — Operating Systems: Deadlock Avoidance, cse02.vlabs.ac.in.

5 · Memory allocation

First-fit, best-fit and worst-fit over memory holes — placement and fragmentation
To place a sequence of process memory requests into a set of free memory partitions (holes) under three contiguous-allocation strategies, to visualise where each process lands, and to measure the resulting internal leftover and external fragmentation.

In contiguous allocation the main memory is a row of holes (free partitions) of various sizes. When a process of size s arrives, the allocator must choose a hole large enough to hold it. First-fit scans from the start and takes the first hole that fits — fast and simple. Best-fit takes the smallest hole that fits, aiming to waste the least space, but it tends to litter memory with tiny unusable slivers. Worst-fit takes the largest hole, hoping the leftover stays big enough to be useful.

After placement the chosen hole shrinks by s; the unused tail remains free. Memory ends up checkerboarded with free fragments — this is external fragmentation: enough total free space exists, but no single hole is large enough for the next request.

leftover of a placement = hole size − process size
External fragmentation = total free space when the next request cannot fit any single hole
Allocated = sum of placed process sizes

Best-fit and first-fit usually outperform worst-fit on utilisation; first-fit is often the fastest in practice. None eliminate external fragmentation — only compaction or paging does.

  1. Open the Simulation tab. A set of memory holes and a queue of process sizes are preloaded.
  2. Edit the holes (free partition sizes) and the process request sizes.
  3. Pick a strategy and press Step to place one process at a time, or Run to place them all.
  4. Watch each process land in a coloured block; the chosen hole and leftover are logged. Failures are flagged.
  5. Read the placed count, total leftover and free space. Compare strategies on the same memory.

Memory map first-fit

Coloured segments are placed processes; dark segments are remaining free space within each partition. Hover order matches the holes list.
Processes placed
0
Failed to place
0
Free space left
--
Internal leftover
--

Configuration

  • Silberschatz, Galvin & Gagne — Operating System Concepts, 10th ed., Ch. 9 (Main Memory). Wiley.
  • Knuth, D. E. — The Art of Computer Programming, Vol. 1, Sec. 2.5 (Dynamic Storage Allocation). Addison-Wesley.
  • Virtual Labs (IIT) — Operating Systems: Memory Allocation, cse02.vlabs.ac.in.

6 · Producer–consumer

Bounded buffer with counting semaphores — step the synchronisation state machine
To synchronise a producer and a consumer sharing a bounded circular buffer using three semaphores, to step the wait and signal operations by hand, and to confirm that the buffer never overflows or underflows and that producer and consumer never corrupt it simultaneously.

The bounded-buffer problem has a producer adding items to a buffer of N slots and a consumer removing them. Three semaphores keep them safe. The counting semaphore empty (initially N) counts free slots; full (initially 0) counts occupied slots; the binary semaphore mutex (initially 1) gives exclusive access to the buffer. A wait (P) decrements a semaphore and blocks if it would go negative; a signal (V) increments it and may wake a waiter.

Producer: wait(empty); wait(mutex); enqueue item; signal(mutex); signal(full)
Consumer: wait(full); wait(mutex); dequeue item; signal(mutex); signal(empty)
invariant: empty + full = N when no thread is inside the critical section

Acquiring the counting semaphore before the mutex is essential: if a thread held the mutex while blocked on a full or empty buffer it would deadlock the other party out of the critical section. With this ordering the buffer never overflows (the producer blocks on empty = 0) nor underflows (the consumer blocks on full = 0), and mutual exclusion guarantees no torn updates.

  1. Open the Simulation tab. Set the buffer capacity N; the three semaphores initialise to empty = N, full = 0, mutex = 1.
  2. Drive the producer with its step button: it runs wait(empty), wait(mutex), enqueue, signal(mutex), signal(full) one operation at a time.
  3. Drive the consumer similarly. Watch the circular buffer fill and drain and the semaphore values change.
  4. Try to over-produce into a full buffer or over-consume an empty one — the offending thread blocks on its semaphore instead of corrupting the buffer.
  5. Use Auto to interleave both threads, and read the invariant empty + full = N holding outside the critical section.

Bounded buffer & semaphores

Producer state: idle  |  Consumer state: idle
empty (free slots)
--
full (used slots)
--
mutex
1
items produced / consumed
0 / 0

Controls

5x
invariant empty + full = N holds outside the critical section.
  • Dijkstra, E. W. — Cooperating Sequential Processes (semaphores, the producer-consumer problem), 1968.
  • Silberschatz, Galvin & Gagne — Operating System Concepts, 10th ed., Ch. 6–7 (Synchronization). Wiley.
  • Downey, A. B. — The Little Book of Semaphores, 2nd ed. Green Tea Press.