I/O Systems
I/O (Input/Output) Systems manage the communication between the computer and external devices. Understanding I/O is crucial for system performance and device management.
Overview
The I/O subsystem consists of:
- I/O Hardware - Physical devices and their controllers
- I/O Software - Device drivers and OS I/O modules
- I/O Interface - Standard methods for device communication
I/O Hardware
Components
flowchart TD
CPU["🖥️ CPU"] <--> Bus["🚏 System Bus"]
Bus <--> C1["🎮 Disk Controller"]
Bus <--> C2["🌐 Network Controller"]
Bus <--> C3["🖥️ Display Controller"]
C1 <--> D1["💾 Disk Drive"]
C2 <--> D2["📡 NIC"]
C3 <--> D3["📺 Monitor"]
Device Controllers
- Interface between device and computer
- Contains registers: data, status, command
- Converts serial bit stream to block of bytes
- Performs error detection/correction
Device Registers
| Register | Purpose |
|---|---|
| Data Register | Holds data being transferred |
| Status Register | Device state (ready, busy, error) |
| Command Register | Commands for the device |
I/O Communication Methods
1. Programmed I/O (Polling)
- CPU continuously checks device status
- CPU explicitly transfers each byte
- Simple but wastes CPU time
while (status != READY) {
// Busy wait - check status
}
read_data();Characteristics:
- CPU is busy waiting
- Simple implementation
- Inefficient for slow devices
- Used for fast, predictable devices
2. Interrupt-Driven I/O
- Device notifies CPU when ready via interrupt
- CPU can do other work while waiting
- More efficient than polling
sequenceDiagram
participant CPU as 🖥️ CPU
participant Dev as 🖨️ Device
CPU->>Dev: 1. Issue I/O Command
Note over CPU: 2. Do other productive work
Dev-->>CPU: 3. Interrupt Signal
Note over CPU: 4. Handle Interrupt & Transfer Data
Note over CPU: 5. Resume Normal Execution
Interrupt Handling Steps:
- Device raises interrupt
- CPU finishes current instruction
- CPU acknowledges interrupt
- CPU saves state (PC, registers)
- CPU jumps to interrupt handler
- Handler processes interrupt
- CPU restores state
- Resume interrupted process
3. Direct Memory Access (DMA)
- Specialized hardware transfers data directly to/from memory
- CPU only involved at start and end
- Best for large data transfers
flowchart LR
CPU["🖥️ CPU"] -->|"Initiates"| DMA["🎛️ DMA Controller"]
DMA <-->|"Direct High-Speed Transfer"| RAM["🧠 Main Memory"]
DMA <-->|"Data Transfer"| Dev["💾 Device"]
DMA Transfer Steps:
- CPU initiates DMA transfer (start address, count, direction)
- DMA controller takes over bus
- DMA transfers data block
- DMA sends interrupt when complete
- CPU handles completion
*DMA Modes:Mode Description Burst Mode DMA holds bus until transfer complete Cycle Stealing DMA takes bus for one cycle at a time Transparent DMA uses bus only when CPU doesn't need it
I/O Software Layers
flowchart TD
L1["👤 User-Level I/O Software
(User programs, libraries)"] L2["⚙️ Device-Independent I/O Software
(OS kernel: buffering, caching)"] L3["🔌 Device Drivers
(Device-specific code)"] L4["⚡ Interrupt Handlers
(Low-level interrupt processing)"] L5["🖥️ Hardware
(Physical devices)"] L1 --> L2 --> L3 --> L4 --> L5
(User programs, libraries)"] L2["⚙️ Device-Independent I/O Software
(OS kernel: buffering, caching)"] L3["🔌 Device Drivers
(Device-specific code)"] L4["⚡ Interrupt Handlers
(Low-level interrupt processing)"] L5["🖥️ Hardware
(Physical devices)"] L1 --> L2 --> L3 --> L4 --> L5
Device Drivers
- Software that controls specific device
- Translate OS requests to device commands
- Handle device-specific details
- Part of kernel (usually)
Device-Independent Software
Functions:
- Uniform interface to device drivers
- Buffering
- Error reporting
- Allocating/releasing devices
- Device-independent block size
Buffering
Temporary storage area for data being transferred.
Why Buffering?
- Speed Mismatch - CPU faster than I/O devices
- Data Size Mismatch - Application vs device block sizes
- Copy Semantics - Ensure data consistency
Buffering Strategies
flowchart LR
subgraph Single["Single Buffering"]
D1["Device"] --> B1["[Buffer]"] --> U1["User"]
end
subgraph Double["Double Buffering"]
D2["Device"] --> BA["[Buffer 1] (Fill)"]
BB["[Buffer 2] (Read)"] --> U2["User"]
end
subgraph Circular["Circular Buffering"]
D3["Device"] --> BC["[B1] → [B2] → [B3] → [B4]"] --> U3["User"]
end
| Strategy | Advantage | Disadvantage |
|---|---|---|
| Single | Simple | Blocking |
| Double | Overlap I/O and processing | More memory |
| Circular | High throughput | Complex management |
Caching
Keeping copies of frequently accessed data in fast storage.
Cache vs Buffer
| Buffer | Cache |
|---|---|
| Holds only existing copy | Holds copy of data from elsewhere |
| For speed matching | For faster access |
| May be only copy | Original always exists |
Disk Cache
- RAM used to cache disk blocks
- Read cache: Recently read blocks
- Write cache: Blocks waiting to be written
Spooling
Simultaneous Peripheral Operations On-Line
- Buffering for slow, non-sharable devices
- Classic example: Print spooling
flowchart LR
P1["Process 1"] --> Spool["🗄️ Spool Queue
(on disk)"] P2["Process 2"] --> Spool P3["Process 3"] --> Spool Spool --> Printer["🖨️ Printer"]
(on disk)"] P2["Process 2"] --> Spool P3["Process 3"] --> Spool Spool --> Printer["🖨️ Printer"]
Benefits:
- Allows concurrent access to non-sharable device
- Process doesn't wait for slow device
- Print order management
I/O Scheduling
Disk Scheduling
Order in which disk I/O requests are serviced.
Goals:
- Minimize seek time
- Maximize throughput
- Fair access
See Disk-Management.md for detailed disk scheduling algorithms
Blocking vs Non-Blocking I/O
Blocking (Synchronous)
- Process waits until I/O completes
- Simple programming model
- Process is suspended
// Blocking read
int n = read(fd, buffer, size); // Waits here until data available
process_data(buffer);Non-Blocking (Asynchronous)
- I/O call returns immediately
- Process continues execution
- Must check for completion later
// Non-blocking read
int n = read(fd, buffer, size); // Returns immediately
if (n == -1 && errno == EAGAIN) {
// Data not ready, do something else
} else {
process_data(buffer);
}Comparison
| Aspect | Blocking | Non-Blocking |
|---|---|---|
| Waiting | Yes | No |
| Complexity | Simple | Complex |
| Responsiveness | Low | High |
| Use Case | Simple apps | Servers, GUIs |
Kernel I/O Subsystem
I/O Scheduling
- Reorder requests to improve performance
- Fairness considerations
Error Handling
- Retry transient failures
- Report errors to applications
- Log errors for diagnosis
Protection
- Prevent unauthorized access
- Validate I/O parameters
- Memory protection during DMA
Power Management
- Device standby/hibernation
- Wake-on-demand
- Power-aware scheduling
Device Types
Block Devices
- Data accessed in fixed-size blocks
- Random access possible
- Examples: HDD, SSD, USB drives
- Commands: read, write, seek
Character Devices
- Data accessed as stream of characters
- Sequential access
- Examples: Keyboard, mouse, serial ports
- Commands: get, put
Network Devices
- Neither block nor character
- Special handling via sockets
- Examples: Ethernet, WiFi adapters
Clock and Timer Devices
- Maintain current time
- Generate interrupts at intervals
- Examples: System clock, hardware timers
I/O Performance
Factors Affecting Performance
- Device Speed - Transfer rate of hardware
- CPU Speed - Interrupt handling, driver processing
- Memory Speed - DMA transfer rates
- Bus Speed - Data path bandwidth
- Software Overhead - Context switches, copying
Performance Metrics
| Metric | Description |
|---|---|
| Throughput | Data transferred per unit time |
| Latency | Time to complete I/O request |
| IOPS | I/O operations per second |
| Utilization | Percentage of time device is busy |
Improving I/O Performance
- Reduce number of context switches
- Reduce data copying
- Use DMA for large transfers
- Use polling for fast, predictable devices
- Balance between polling and interrupts
- Use efficient data structures