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:

  1. 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.
  2. 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;
    }
    

  3. Write the pseudo-code for a process context switch in the CPU scheduler.
  4. 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);
    }
    

  5. What is a microkernel? What are the advantages and disadvantages of the microkernel approach?
  6. Key points about microkernels: The main advantage of a microkernel is reliability/fault tolerance. 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.

  7. What is the difference between a non-preemptive and a preemptive scheduler?
  8. 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.