Device Management
1. Device Independence
Device indepence is the separation of the logical properties of a device from its physical properties. This includes the device type and device instance, and the device variations. This includes:
- The unit of data transfer (e.g. character, block).
- The supported operations (e.g. read, write, seek).
- Synchronous or asynchronous operation.
- Speed differences.
- Shareable (e.g. disks) or single-user (e.g. printers).
- Types of error conditions.
There are many IO Layers:
- User Level IO Software.
- Device independent operating system software.
- Device drivers.
- Interrupt handlers.
- Hardware.
1.1 Interrupt Hnadler
- On character devices (one byte at a time), the interrupt handler is called for each byte when a character is transfered. It processes the next byte.
- On block devices (multiple bytes at a time), the interrupt handler is called when the entire block is transfered. It is a signal device handler.
1.2 Device Drivers
A device driver handles one device type, but may control multiple devices of the same time. It:
- Implements block read / write.
- Accesses device registers.
- Initiates device operations.
- Schedules requests.
- Handles errors.
1.3 Device Independent OS Software
The device independent layer provides device independence. It:
- Maps logical to physical devices.
- Requests validation against device characteristics.
- Allocates dedicated devices.
- Protects / user access validation.
- Buffering for performance and block size independence.
- Error reporting.
2. Device Allocation
Dedicated devices (e.g. printer):
- Have a simple policy (open fails if already opened, etc.)
- Allocated for long periods.
- Only allocated to authorized processes.
Shared devices (e.g. disks)
- OS provides file system for disks...
Spooled devices (e.g. printers):
- Printer output saved to disk file
- File printed later by spooler daemon
- Printer only allocated by daemon. No process is allowed direct access.
3. Buffering
When we buffer IO:
- For output, user data is transferred to the OS output buffer. Process continues and only suspends when the buffer is full.
- For input, OS reads ahead, and reads are (normally) satisfied from buffer. Process blocks when the buffer is empty.
Buffered IO is used to smooth peaks in IO traffic, and caters for differences in data transfer units between devices. In unbuffered IO:
- Data is transfered directly from user space to/from the device. Each read and write causes physical IO, and implies a device handler is used for each transfer.
- High process switching overhead (e.g. per character).
4. User Interface
The user interface for IO contains open, close, read, write and seek. This must be device independent, but may support synchronous or asynchronous operations, and blocking or non-blocking operations.
5. Device Drivers
There are 3 main ways to do IO:
- Programmed IO - CPU is used to transfer data between memory and device.
- Interrupt driven IO - CPU is interrupted when device is ready.
- IO using Direct Memory Access (DMA) - Device controller transfers data directly to memory without CPU intervention.
6. Blocking vs Non Blocking IO
A blocking IO call returns when the operation completes. The process is suspended, and the IO appears instantaneous. It is easy to understand, but leads to multithreaded code.
Non-Blocking IO call returns as much as available (e.g. read with fcntl system call. It provides application-level polling for IO.
7. Asynchronous IO
In asynchronous IO, processes exeucute in parallel with IO operations. There is no blocking in the interface procedure.
- IO subsystem notifies the process upon completion using a callback function, process signal, etc.
- Supports check / wait if IO operation completed.
- Very flexible and efficient.
- Harder to use and potentially less secure.