COS 318: Operating Systems, Fall 2013
Quiz 1: OS Structure, Processes, and Threads
Due: 11:55pm, Wednesday, October 2
This quiz checks your comprehension of the reading assignments and
material presented in class. It covers lectures from 9/17 through
9/26. You may reference the textbook, lecture slides, and your notes.
Online sites (e.g., Wikipedia) may also be consulted but you must
cite them in your writeup.
Each question is worth three points. Please strive for clarity and
brevity in your answers. Essay questions should require no more than
one or two short paragraphs. Pseudo-code should be in the form of
short descriptive English statements.
Submit your answers by clicking the "submit" link on the lecture
schedule page. Only online submissions will be accepted. Please
submit plain ASCII text files.
Questions:
- Write the pseudo-code for a system call. Describe both what
happens in user-space (e.g., within a library routine) and in
kernel-space. Assume that the system call parameters are passed in
registers.
We covered this in the "OS Structure" lecture, slides 22 and 23.
Suggested solution:
# A generic library call
int foo (void *arg1, void *arg2, ..., void *argn) {
int result;
move arg1 to R_1;
move arg2 to R_2;
...
move argn to R_n;
move FOO to R_0;
# Trap to kernel
int $0x80;
move R_result to result;
return result;
}
--- User - kernel boundary ---
# The currently running process
Process *current;
# Array of system call handler functions
typedef int (*SYSCALL_HANDLER)(void);
const SYSCALL_HANDLER sysent[] = {
handler1,
handler2,
...
handlerN
}
# The syscall entry point in the kernel
void syscall_entry(void) {
SYSCALL_HANDLER handler;
int index, result;
save_context(current);
use_kernel_stack(current);
# Look up system call handler
move R_0 to index;
handler = sysent[index];
# Call it. We're assuming args are still in registers...
result = handler(void);
move result to R_result;
use_user_stack(current);
restore_context(current);
# Switch to user mode and return
iret;
}
- Write the pseudo-code for a process context switch in the CPU
scheduler.
Suggested solution:
Process *current;
void schedule(void) {
Process *next;
save_context(current);
flush_cache_and_TLB();
next = choose_ready_process();
next->state = RUNNING;
restore_context(next);
current = next;
jump_to_PC(next);
}
- What is a microkernel? What are the advantages and disadvantages
of the microkernel approach?
Key points about microkernels:
- The aim is to do as much work as possible in user space.
- It has a small kernel, typically providing the process and IPC
abstractions, and handling CPU scheduling and interrupts.
- It implements OS services such as device drivers, network protocol
stacks, file systems, etc., as user-space processes.
- Requests by a user process for an OS service involve exchanging
messages with possibly many OS service processes.
The main advantage of a microkernel is reliability/fault tolerance.
- OS services are modularized as processes. Since they do not share
memory, they cannot read or corrupt the state of other OS services.
- The crash of an OS service does not crash other services or the
kernel.
- It may be possible to restart a failed OS service.
The main disadvantage is performance overhead. A single request for
an OS service may require multiple messages to be exchanged between
processes, leading to multiple system calls and context switches.
- What is the difference between a non-preemptive and a preemptive
scheduler?
A non-preemptive scheduler will not take the CPU away from a running
thread -- the thread must explicitly call yield() or block() to
surrender the CPU. A preemptive scheduler may decide to suspend the
currently running thread and run a different thread in response to a
timer or I/O interrupt.