OS Answers
OS Answers
An operating system provides two broad categories of services: (A) Services for users and programs,
and (B) Services for efficient system operation.
2. Program Execution
The OS loads a program into memory, runs it, and handles normal/abnormal termination. It manages
the process lifecycle completely.
3. I/O Operations
Provides access to I/O devices (keyboard, disk, network). User programs do not directly control
devices; the OS intermediates to ensure safety and efficiency.
4. File-System Manipulation
Programs need to create, read, write, delete files and directories. The OS provides file system
management including permission control and directory organization.
5. Communications
Processes communicate either on the same computer or across a network. The OS supports:
• Shared Memory: Processes read/write a common memory region
• Message Passing: OS transfers packets of information between processes
6. Error Detection
The OS must detect and handle errors in CPU, memory hardware, I/O devices, and user programs. It
takes appropriate action to ensure consistent operation (e.g., halting a failing process).
8. Accounting
The OS tracks which users use how much of which resources. Used for billing, system tuning, and
audit trails.
2. Layered Approach
The OS is divided into N layers. Layer 0 is hardware; Layer N is the user interface. Each layer uses
only services from the layer directly below it.
• Advantages: Modularity, easier debugging (one layer at a time)
• Disadvantages: Performance overhead from multiple layer traversals; difficult to define layer
boundaries
4. Microkernel Structure
Moves as much functionality as possible out of the kernel into user space. The microkernel handles
only the most essential functions: basic inter-process communication, minimal memory management,
and basic scheduling.
• User-space servers handle file system, device drivers, network, etc.
• Communication via message passing
• Benefits: More reliable, secure, easier to port and extend
• Drawback: Performance overhead due to user-kernel space communication
• Examples: Mach, QNX, MINIX
Mechanism:
When a system call is made, the CPU switches from user mode to kernel mode (via a trap/interrupt),
executes the requested service, then returns to user mode. A system call number indexes into a
system call table that maps to the kernel function.
1. fork()
Creates a new child process by duplicating the calling (parent) process.
• The child gets a copy of the parent's address space (code, data, stack)
• Returns 0 to child, child's PID to parent, -1 on error
• Child and parent execute concurrently after fork()
Example (C Code):
pid_t pid = fork();
if (pid == 0) { /* Child process */ }
else { /* Parent process */ }
2. exec()
Replaces the current process's memory image with a new program. Often called after fork() to load a
different program into the child process.
• exec() family includes: execl(), execv(), execle(), execve(), execlp(), execvp()
• Does not return on success; the process's code, data, heap, and stack are replaced
• PID remains the same after exec()
Example (C Code):
execlp("/bin/ls", "ls", NULL); // Replace process with 'ls' command
3. wait() / waitpid()
Causes the parent process to suspend execution until one of its child processes terminates. Used to
collect the exit status of child processes and prevent zombie processes.
• wait(NULL) waits for any child to finish
• waitpid(pid, status, options) waits for a specific child
• Returns the PID of the terminated child
Example (C Code):
int status;
pid_t child = wait(&status); // Parent waits
4. exit()
Terminates the calling process and returns an exit status to the parent. The OS reclaims all resources
(memory, file descriptors) allocated to the process.
• exit(0) typically means success; non-zero means error
• Triggers cleanup of atexit() registered functions and flushes stdio buffers
• Parent receives the exit status via wait()
Example (C Code):
exit(0); // Normal termination
exit(1); // Abnormal termination
5. getpid() / getppid()
Returns the Process ID (PID) of the calling process or its parent's PID (PPID). PIDs are used by the OS
to uniquely identify and manage processes.
• getpid(): Returns current process's PID
• getppid(): Returns parent process's PID
• Useful in fork() logic to distinguish parent and child
Example (C Code):
pid_t my_pid = getpid();
pid_t parent_pid = getppid();
Admitted
┌─────┐ ─────────────────────► ┌───────┐
│ NEW │ │ READY │
└─────┘ └───┬───┘
Scheduler│ ▲ Interrupt /
Dispatch │ │ I/O Complete
▼ │
┌──────────┐ ┌──────────────────┐
│ WAITING │ ◄──────── │ RUNNING │
│(BLOCKED) │ I/O Req. │ (On CPU) │
└──────────┘ └────────┬─────────┘
│ Exit
▼
┌────────────┐
│ TERMINATED │
└────────────┘
Explanation of Transitions
Key Metrics
• CPU Utilization: Percentage of time CPU is busy
• Throughput: Number of processes completed per unit time
• Turnaround Time: Total time from submission to completion (waiting + execution + I/O)
• Waiting Time: Time spent in the ready queue waiting for CPU
• Response Time: Time from submission to first response
Example:
Process Burst Time Arrival Time
P1 24 ms 0
P2 3 ms 0
P3 3 ms 0
3. Priority Scheduling
Each process has a priority. CPU is assigned to the highest-priority process. Ties broken by FCFS. Can
be preemptive or non-preemptive.
Example:
Process Burst Time Priority
P1 10 ms 3
P2 1 ms 1 (highest)
P3 2 ms 4
P4 1 ms 5 (lowest)
P5 5 ms 2
4. Round-Robin (RR)
Designed for time-sharing. Each process gets a fixed time quantum (e.g., 4 ms). After its quantum, it's
preempted and placed at the end of the ready queue. Preemptive.
Gantt Chart: P1(0-4) | P2(4-7) | P3(7-10) | P1(10-14) | P1(14-18) | P1(18-22) | P1(22-26) | P1(26-30)
Waiting Times: P1=6, P2=4, P3=7 | Average = 17/3 = 5.66 ms
• Advantage: Fair; no starvation; good for time-sharing
• Disadvantage: Higher average turnaround time; quantum size critical
5. Multilevel Queue Scheduling
Ready queue is split into multiple queues by process type (system, interactive, batch, student). Each
queue has its own algorithm. Processes are permanently assigned to a queue.
• Foreground (interactive) queue: RR scheduling
• Background (batch) queue: FCFS scheduling
• Each queue has priority; starvation possible for lower queues
1. Many-to-One Model
Many user-level threads are mapped to a single kernel thread. Thread management is done in user
space.
Diagram:
User Space: [T1] [T2] [T3] [T4]
\ | | /
Kernel Space: [K1]
Advantages Disadvantages
Efficient thread management in user space If one thread blocks on I/O, all threads block
No kernel involvement for context switch Cannot run threads in parallel on multicore
Portable across OS Limited scalability
Examples: Solaris Green Threads, GNU Portable Threads
2. One-to-One Model
Each user-level thread maps to exactly one kernel thread. The kernel schedules each thread
independently.
Diagram:
User Space: [T1] [T2] [T3]
| | |
Kernel Space: [K1] [K2] [K3]
Advantages Disadvantages
True parallelism on multicore processors Creating many threads creates many kernel
threads (overhead)
One thread blocking does not block others System may limit the number of kernel threads
Better concurrency support More expensive context switching
Examples: Linux, Windows NT/XP/2000
3. Many-to-Many Model
Many user-level threads are multiplexed onto an equal or smaller number of kernel threads. The OS
creates as many kernel threads as needed.
Diagram:
User Space: [T1] [T2] [T3] [T4] [T5]
\ | \ / | /
Kernel Space: [K1] [K2] [K3]
Advantages Disadvantages
Combines benefits of both models Complex to implement
Can create as many user threads as needed Requires kernel-user coordination (scheduler
activations)
Threads can run in parallel Debugging is harder
Examples: Solaris (prior to v9), Windows with ThreadFiber
4. Two-Level Model
Similar to Many-to-Many, but also allows a specific user thread to be bound to a specific kernel thread
(one-to-one binding when needed). Provides flexibility.
• Can use M:M for most threads and 1:1 for real-time or critical threads
• Examples: IRIX, HP-UX, Tru64 UNIX, Solaris 8 and earlier
Inter-Process Communication (IPC) refers to mechanisms that allow processes to communicate and
synchronize with each other. Two fundamental models exist:
• Shared Memory: A region of memory shared between processes
• Message Passing: Processes communicate by sending/receiving messages
1. Shared Memory
A shared memory region is created in the address space accessible to multiple cooperating processes.
Processes read and write to this common area directly.
Block Diagram:
┌───────────┐ ┌──────────────────┐ ┌───────────┐
│ Process A │ ───► │ SHARED MEMORY │ ◄─── │ Process B │
│(Producer) │ │ (Common Buffer) │ │(Consumer) │
└───────────┘ └──────────────────┘ └───────────┘
2. Message Passing
Processes communicate by sending and receiving messages through the OS. No shared variable
needed. Useful in distributed systems.
Block Diagram:
┌───────────┐ send(msg) ┌─────────────┐ recv(msg) ┌───────────┐
│ Process A │ ──────────────► │ Message │ ─────────────► │ Process B │
└───────────┘ │ Queue/Link │ └───────────┘
└─────────────┘
3. Pipes
A pipe is a unidirectional communication channel between two related processes (typically parent and
child). Data is written at one end and read from the other.
Block Diagram:
┌───────────┐ write(fd[1]) ┌──────────┐ read(fd[0]) ┌───────────┐
│ Process A │ ──────────────► │ PIPE │ ─────────────► │ Process B │
└───────────┘ └──────────┘ └───────────┘
4. Sockets
A socket is an endpoint for communication. Two sockets (one at each end of the connection) form a
socket pair. Used for both local (Unix domain sockets) and network communication (TCP/IP).
Block Diagram:
┌─────────┐ Socket Pair ┌─────────┐
│ Host A │ ◄────────────────► │ Host B │
│IP:Port A│ Network/Local │IP:Port B│
└─────────┘ └─────────┘
5. Signals
Signals are software interrupts sent to a process to notify it of an event (e.g., SIGKILL, SIGTERM,
SIGSEGV). The process handles the signal via a signal handler.
• Asynchronous: Can arrive at any time
• Predefined signal set (kill -l lists all)
• Used for inter-process notification (e.g., parent notifying child)
Semaphores
A semaphore is a synchronization tool. It is an integer variable S accessed only through two atomic
operations:
• wait(S) [also called P(S) or down(S)]: Decrements S. If S <= 0, the process blocks
• signal(S) [also called V(S) or up(S)]: Increments S. May wake a blocked process
Types of Semaphores:
• Binary Semaphore (Mutex): Value is 0 or 1. Used for mutual exclusion
• Counting Semaphore: Can take any non-negative value. Used for resource counting
Constraints:
• Producer must not produce into a full buffer
• Consumer must not consume from an empty buffer
• Only one process should access the buffer at a time (mutual exclusion)
Semaphore-Based Solution
Three semaphores are used:
• mutex (binary): Initialized to 1 - ensures mutual exclusion on the buffer
• empty (counting): Initialized to N (buffer size) - counts empty slots
• full (counting): Initialized to 0 - counts filled slots
Producer() {
while (true) {
produce_item(item); // Create a new item
This semaphore-based solution is elegant, correct, and widely used in OS implementations for
producer-consumer style problems including disk I/O buffers, print spoolers, and network packet
queues.