As an example of how multiprogramming handles I/O requests we will study how to wait for the user to input data from the keyboard.
Key-presses are asynchronous and external
A user pressing a key on a keyboard is not an internal event, nor is a key-press synchronous, a keypress can happen at any time independent of the executing program.
Normally the operating system is responsible for handling user input and output. When a user program requests service from the operating system this is implemented as system calls.
System calls
System calls forms an interface between user programs and the operating system.
We will start by to study how to implement a system call that lets the user input a single character from the keyboard. Next we will study how to implement a system call that lets the user input a string from the keyboard.
Let’s sketch the design for a system call similar to the C
library function getc
that allows a program to read a single single character typed by a human user on
the keyboard.
The below figure shows an example where job 1 calls the custom getc
system
call and job 2 executes while job 1 waits for the user to press a key on
the keyboard.
In the above figure important events are marked with a number inside a yellow circle.
getc
system call to read a character from the
keyboard.getc
system call to complete.The result of the getc
system call can not be obtained immediately, the kernel
must wait for the user to press a key on the keyboard. When handling the getc
system call, the kernel blocks the caller and make another job run until the
user presses a key on the keyboard.
A null-terminated string is a character string stored as an array containing
the characters and terminated with a null character \0
.
1
We have already studied how interrupts can be used to wait for a single keypress from a human user. How can we design a system call for inputting a string?
Where should the input buffer be allocated? In user space or in kernel space?
To enforce memory safety user programs are not allowed to access (read or write) kernel data but the kernel is allowed to read and write data in user space.
The kernel must know the address (pointer) to the input buffer in user space.
The kernel must know the size of the input buffer and decide what to do when the buffer is full.
To better understand the details of how the read string system call can be implemented we will study a small example with two jobs. In this example, job 1 allocates a 3 element input buffer and uses a system call to request the operating system to wait (using interrupts) for the user to fill this buffer with two characters and terminate the buffer with null. Until the input buffer is full the operating system (kernel) let job 2 execute between keyboard interrupts.