CS 438, Operating Systems Analysis

Test 2, 2 November 2004 - Device Management


  1. Consider the mouse. Would you prefer that a mouse driver be interrupt driven or polling? Explain.


    The mouse is a slow, low-data rate device, so making it polling isn't a big deal.


  2. A colleague of yours is modifying a device driver that has synchronous (that is, blocking) read and write operations. Your colleague needs to improve the performance of the processes using the device driver and wants to make the read and write operations asynchronous (that is, non-blocking). Unfortunately, your colleague only has time to change one or the other of the operations and is unsure which one should be changed. What advice would you give your colleague? Explain.


    Implementing an asynchronous write would seem to make the most sense. Once a process has written data, it is done with that data and may move on to other data; there is no need to wait for the data write to finish. On the other hand, when reading data, the process may be able to do other things, but can't proceed with its main-line processing until the data show up. The performance advantages to an asynchronous write are always available, but the performance advantages to an asynchronous read depends on the process's ability to find other things to do while the read takes place.

    The answer gets more complicated if you look at the storage being used to hold the data. In this case the writes are equivalent to reads because, while the data may not matter, the storage holding the data does, and the writing process has to wait until the OS is done reading the storage before the process can write it again. This can be dealt with using double buffering, but the same technique can be used for reading too. There is still, however, a slight advantage to writing over reading due to the potential delay required when the read buffer is filling for the first time.


  3. Explain how you could implement binary semaphores on a system with a scheduler using priority-based selection.


    The idea is to get mutual exclusion while in the semaphore's get() and put() operations. The easiest way to do that on a priority-based selection scheduler is to raise the priority of the calling process to its maximum for the duration of the calls:

    old_p = set_priority(max_p)
      // access semaphore data
    set_priority(old_p)
    

    For safety, max_p should be a high priority reserved for use by semaphores (and other OS structures providing mutual exclusion).


  4. A colleague remembers the buffer synchronization for producer-consumers as

    p() 
      while true
        begin_cs()
          while not empty { }
          buffer = p()
          empty = false
        end_cs()
    
    c()
      while true
        begin_cs()
          while empty { }
          c(buffer)
          empty = true
        end_cs()
      

    Assuming empty is initially false, is this correct? Explain. Note that this question is asking whether or not the code is correct, not whether or not it is well written.


    Given the incorrect initial value for empty, this question turned out to be tricker to answer than I anticipated. Let me first given the answer I was trying to elicit, and then I'll deal with the empty is false assumption.

    The problem with your colleague's code is that the critical section in both cases is too large. A process waiting for empty to become a particular value (true for the consumer and false for the produce) will spin within the critical section, which blocks out the other process from ever changing empty.

    Now for the initial value of empty. For the most part, the initial value of empty is irrelevant to the answer for this question; I had added the clause to keep people from getting side-tracked about the initial value of empty (of course, by getting the initial value wrong, exactly the opposite effect occurred). Given the false initial value, you have to make a further assumption to answer the question: the state of the buffer itself. If you assume the buffer contains garbage (which is an inconsistent assumption, although one you're allowed to make) then another problem could be that the first read by the consumer returns garbage if the consumer enters the critical section first. If you assume the buffer contains data, the initial value of empty doesn't matter.



This page last modified on 14 November 2004.