Midterm Solutions and Comments

22C:116, Spring 1999

Douglas W. Jones

Grade Distribution

Average = 9.9 Median = 10.8
                 X                               X X
      ___________X_X_X_X_______X___X___X_X_X___X_X_X_X_X_X_X_______
      . 2 . 3 . 4 . 5 . 6 . 7 . 8 . 9 . 10. 11. 12. 13. 14. 15. 16.
Grades?             C      |||      B      |||      A
The grade scale suggested above is intended as only the roughest of guides!

Solutions and Comments

  1. What test should be done on a Multics system by the code for a system call such as read(f,buffer,len) to verify that it is reading into a buffer the user is allowed to manipulate?

    The key question for the example is, does the user's ring (privilege level) allow manipulation of the memory segment(s) at addresses buffer to buffer+len. The hardware will not make this kind of check, so on receipt of any pointer parameter at a gateway, the code for that gateway must find the caller's ring, find the ring number of the segment referenced by any pointer parameters, and then compare these ring numbers to see if the caller had the right to perform the intended operations on those segments.

    4 students did well here, 7 gave relevant answers, and the remainder earned only a small amount by vague answers that, at best, demonstrated correct understanding of the question.

  2. On the Hawk machine, what must a kernel function do to access the memory pointed to by a pointer passed by the user?

    Once the kernel function retrieves a pointer parameter from the saved values of a user register, to follow that pointer, it must first break the pointer into page and word-in-page fields. Second, it must look in the user's virtual address map to find the current mapping of the page. If the page is not in main memory, it must handle the case as a page fault and wait until the necessary page is in main memory. Then, it must find the page frame that is used and compose this with the word-in-page field in order to compute the physical address of the referenced word.

    5 students did well here, 4 gave relevant answers, and the remainder earned only a small amount by vague answers that, at best, demonstrated correct understanding of the question.

  3. How could kernel code on the Hawk machine call a user function and how would the kernel regain control when the user function attempted to return?

    The kernel cannot directly call user code -- user code runs in a different address space with different privilege levels! Instead, the kernel can first save the user's PC and registers, and second, set the user's PC to the address of the user function that is to be called. Returning control to the kernel after the user's routine is called is more difficult! One way to do this is for the kernel to force the call to the user function with a bogus return address. When the user function attempts to return, it will attempt a fetch from this address, forcing a trap; on intercepting such a trap, the kernel can then restore the saved state of the user process and take whatever actions are needed before resuming normal system operation.

    6 did well here, 4 more had good call mechanisms but no clear return mechanism, and all but one of the remainder received at least some credit.

  4. Illustrate the potential for parallelism in a sytem where many disk drives are attached to one DMA controller, where the drives have an operation that seeks a cylinder without initiating a transfer, and where the completion of any operation on any drive causes an interrupt.

    If a separate "elevator" is maintained for each drive, as soon as a drive finishes the last scheduled transfer on one cylinder, a seek may be issued for that drive while the interrupt handler then shifts its attention to the next drive that has pending requests and has completed its seek operation to the required cylinder. Thus, seek operations on one drive and data transfer operations on another may be overlapped.

    This was perhaps the easiest problem on the exam. 13 did well here, and 2 more had answers that were poorly constructed but basically sound.

  5. Discuss the potential for implementing an on-board disk scheduler for a disk with an on-board controller with considerable buffer capacity, used as a cache. Does this eliminate the need for disk scheduling in the OS? Would it work better for read or for write? Would an OS scheduler work better after some tradeoff point?

    Certainly, if a number of writes are made to such a disk, the on-board cache can buffer all the data and then the on-board scheduler can write them to disk in the optimal order. On the other hand, if the system assumes the usual disk semantics, it will not issue a new read operation until the previous one has completed, and therefore, the on-board scheduler will be unable to optimize the order of read operations. Therefore, it is still useful to put a disk scheduler in the operating system, and the on-board scheduler clearly works better for write scheduling than for read scheduling. The on-board scheduler will work best for write-mostly disk traffic (rare) or for single-threaded read traffic. The scheduler is not well suited to handling read traffic from multiple independant threads, where system-level schedulers can reorder writes quite freely.

    Only 2 got all three parts of this question. 4 more got 2 of the 3 parts, and one more got one part right. 3 students focused their answer on the choice between on-board cache and system-level cache structures, with no reference to scheduling.

  6. What must be stored in the frame-table entry for the page frame holding the page table for a segment, on a paged-segmented machine, where segments may be shared between the address spaces of different users.

    A frame may hold: A page, the page-table for a segment, or the segment table for a process. Therefore a frame-table entry needs a tag to distinguish between these. If the frame contains the page-table for a non-shared segment, the corresponding entry must include a pointer to the segment table of the process that has the segment, and the virtual address of this segment in that address space. If the segment is shared, the entry must include pointers to the segment tables of all processes that share this segment, along with the corresponding virtual addresses. Usually, this will not be stored as literal information in the table, but rather, the frame-table entry will contain a pointer to the list of users of the segment.

    Only 1 student gave a good answer, 3 more gave relevant answers that made reference to sharing, 3 more ignored sharing, and 3 stopped after noting that the entry would contain a pointer to the segment table. Many received little or no credit here.

  7. Explain why CDR-coding reduced the page fault rate.

    CDR coding reduces the page fault rate because it reduces the fragmentation of lists, or alternately, it improves the locality of reference when a program scans down a linked list.

    6 gave good answers, 9 more had minor proglems, and 3 had larger problems in answers that were still largely correct.

  8. Contrast these alternatives for allocating space for kernel data structures on a virtual memory machine. One way is to lock a contiguous range of page frames for the kernel's heap, the other is to allow the kernel to claim and locks random free page frames, as needed.

    If the kernel locks a contiguous range, the kernel heap is compact, minimizing the impact of external fragmentation, but also minimizing the availability of page frames to user applications when the kernel no-longer needs them. If page frames are claimed on demand, the heap will be discontiguous, and this may lead to external fragmentation, but it makes it easy for the kernel to return unneeded page frames to general circulation. As a result, the compact kernel heap would work best if the size of the kernel heap was unlikely to vary greatly over the life of the system, while the demand allocation scheme would be most desirable if the kernel heap size varied considerably, and it would work particularly well if kernel data structures were designed to minimize external fragmentation, for example, by having block sizes that are simple fractions of the page size.

    3 did well here, 3 more did reasonably, and 4 more correctly identified at least one major issue. 4 gave no answer and 2 more wrote at length while distracted by ephemeral issues, and therefore earned very little credit.

  9. What is it about the implementation of signal() given in the exam that precludes it from being called within an interrupt service routine?

    The given implementation ended by enabling interrupts. If this was called within an interrupt service routine, it could enable interrupts prematurely, thus causing the interrupt service routine to be interrupted at an unacceptable point.

    5 did well here. 4 identified the fact that it disables interrupts as the problem, while 4 more gave wandering answers touching on such things as mutual exclusion, priority, or deadlock. 6 got no credit.

  10. Comment on some of the major problems you would have to solve to implement a UNIX-style fork() operation as part of our thread manager.

    To implement a UNIX-style fork() operation, our thread manager would have to duplicate the contents of the stack segment of the calling thread. Mere duplication, however, would not work, because of the possibility that the local variables of one function called by the thread would contain pointers to other local variables on the same stack. Therefore, our implementaiton of fork would have to require that all variables passed by reference be either global or allocated on the heap, and not local variables of some other function.

    None did really well here, but 4 got partial credit for addressing something relevant to the question, while 11 more wrote at length without addressing any key issues.