From: Ben Pfaff Date: Fri, 17 Sep 2004 06:51:46 +0000 (+0000) Subject: Update docs. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pintos-anon;a=commitdiff_plain;h=7a48d9a0ac4176681da03e878061b0c59e5bade4 Update docs. --- diff --git a/doc/standards.texi b/doc/standards.texi index 4b3bbef..1434a63 100644 --- a/doc/standards.texi +++ b/doc/standards.texi @@ -65,9 +65,10 @@ There are a few exceptions: @itemize @bullet @item -Project 1 has a few parts that we must be able to turn on and off via -conditional compilation. You must use the macros we specify for those -parts. +Problem 1-4, the advanced scheduler. We must be able to turn this on +and off with a compile time directive. You must use the macro name we +specify for that part. @xref{Problem 1-4 Advanced Scheduler}, for +details. @item Code written for extra credit may be included conditionally. If the diff --git a/doc/threads.texi b/doc/threads.texi index 168ee79..fbd8ac3 100644 --- a/doc/threads.texi +++ b/doc/threads.texi @@ -174,7 +174,7 @@ directories and page tables. This will be more important to you in project 3. For now, you can ignore it. @end table - +FIXME devices and lib directories? @node Debugging versus Testing @section Debugging versus Testing @@ -205,6 +205,7 @@ thread switches. That means that running the same test several times doesn't give you any greater confidence in your code's correctness than does running it only once. +FIXME So, to make your code easier to test, we've added a feature to Bochs that makes timer interrupts come at random intervals, but in a perfectly predictable way. In particular, if you put a line @@ -234,21 +235,22 @@ be justified in your @file{DESIGNDOC} file. If you're not sure you're justified, ask! While all parts of this assignment are required if you intend to earn -full credit on this project, keep in mind that Problem 2 (Join) will +full credit on this project, keep in mind that Problem 1-2 (Join) will be needed for future assignments, so you'll want to get this one right. We don't give out solutions, so you're stuck with your Join -code for the whole quarter. Problem 1 (Alarm Clock) could be very +code for the whole quarter. Problem 1-1 (Alarm Clock) could be very handy, but not strictly required in the future. The upshot of all this is that you should focus heavily on making sure that your -implementation of Join works correctly, since if it's broken, you will -need to fix it for future assignments. The other parts can be turned -off in the future if you find you can't make them work quite right. +implementation of @code{thread_join()} works correctly, since if it's +broken, you will need to fix it for future assignments. The other +parts can be turned off in the future if you find you can't make them +work quite right. -Also keep in mind that Problem 4 (the MLFQS) builds on the features you -implement in Problem 3, so to avoid unnecessary code duplication, it +Also keep in mind that Problem 1-4 (the MLFQS) builds on the features you +implement in Problem 1-3, so to avoid unnecessary code duplication, it would be a good idea to divide up the work among your team members -such that you have Problem 3 fully working before you begin to tackle -Problem 4. +such that you have Problem 1-3 fully working before you begin to tackle +Problem 1-4. @node Problem 1-1 Alarm Clock @section Problem 1-1: Alarm Clock @@ -276,18 +278,30 @@ in milliseconds or some other unit. @node Problem 1-2 Join @section Problem 1-2: Join -Implement @code{thread_join(struct thread *)} in -@file{threads/thread.c}. There is already a prototype for it in -@file{threads/thread.h}, which you should not change. This function -causes the currently running thread to block until thread passed as an -argument exits. If A is the running thread and B is the argument, -then we say that ``A joins B'' in this case. +Implement @code{thread_join(tid_t)} in @file{threads/thread.c}. There +is already a prototype for it in @file{threads/thread.h}, which you +should not change. This function causes the currently running thread +to block until the thread whose thread id is passed as an argument +exits. If A is the running thread and B is the argument, then we say +that ``A joins B'' in this case. + +Incidentally, we don't use @code{struct thread *} as +@file{thread_join()}'s parameter type because a thread pointer is not +unique over time. That is, when a thread dies, its memory may be, +whether immediately or much later, reused for another thread. If +thread A over time had two children B and C that were stored at the +same address, then @code{thread_join(@r{B})} and +@code{thread_join(@r{C})} would be ambiguous. Introducing a thread id +or @dfn{tid}, represented by type @code{tid_t}, that is intentionally +unique over time solves the problem. The provided code uses an +@code{int} for @code{tid_t}, but you may decide you prefer to use some +other type. The model for @code{thread_join()} is the @command{wait} system call in Unix-like systems. (Try reading the manpages.) That system call can only be used by a parent process to wait for a child's death. You should implement @code{thread_join()} to have the same restriction. -That is, a thread may only join on its immediate children. +That is, a thread may only join its immediate children. A thread need not ever be joined. Your solution should properly free all of a thread's resources, including its @code{struct thread}, @@ -300,9 +314,8 @@ multiple times is equivalent to joining it once, because T has already exited at the time of the later joins. Thus, joins on T after the first should return immediately. -The behavior of calling @code{thread_join()} on an thread that is not -the caller's child is undefined. You need not handle this case -gracefully. +Calling @code{thread_join()} on an thread that is not the caller's +child should cause the caller to return immediately. Consider all the ways a join can occur: nested joins (A joins B when B is joined on C), multiple joins (A joins B, then A joins C), and so @@ -315,15 +328,23 @@ Be careful to program this function correctly. You will need its functionality for project 2. @node Problem 1-3 Priority Scheduling -@section Problem 1-3 Priority Scheduling - -Implement priority scheduling in Pintos. Priority -scheduling is a key building block for real-time systems. Implement functions -@code{thread_set_priority()} to set the priority of a thread and -@code{thread_get_priority()} to get the priority of a thread. There -are already prototypes for these functions in @file{threads/thread.h}, +@section Problem 1-3: Priority Scheduling + +Implement priority scheduling in Pintos. Priority scheduling is a key +building block for real-time systems. Implement functions +@code{thread_set_priority()} to set the priority of the running thread +and @code{thread_get_priority()} to get the running thread's priority. +(A thread can examine and modify only its own priority.) There are +already prototypes for these functions in @file{threads/thread.h}, which you should not change. +Thread priority ranges from @code{PRI_MIN} (0) to @code{PRI_MAX} (59). +The initial thread priority is passed as an argument to +@code{thread_create()}. If there's no reason to choose another +priority, use @code{PRI_DEFAULT} (29). The @code{PRI_} macros are +defined in @file{threads/thread.h}, and you should not change their +values. + When a thread is added to the ready list that has a higher priority than the currently running thread, the current thread should immediately yield the processor to the new thread. Similarly, when @@ -347,17 +368,17 @@ You will need to account for all different orders that priority donation and inversion can occur. Be sure to handle multiple donations, in which multiple priorities are donated to a thread. You must also handle nested donation: given high, medium, and low priority -threads H, M, and L, respectively, and supposing H is waiting on a -lock that M holds and M is waiting on a lock that L holds, both M and -L should be boosted to H's priority. +threads H, M, and L, respectively, if H is waiting on a lock that M +holds and M is waiting on a lock that L holds, then both M and L +should be boosted to H's priority. You only need to implement priority donation when a thread is waiting -for a lock held by a lower-priority thread. You do not need to +for a lock held by a lower-priority thread. You do not need to implement this fix for semaphores, condition variables or joins. However, you do need to implement priority scheduling in all cases. @node Problem 1-4 Advanced Scheduler -@section Problem 1-4 Advanced Scheduler +@section Problem 1-4: Advanced Scheduler Implement Solaris's multilevel feedback queue scheduler (MLFQS) to reduce the average response time for running jobs on your system. @@ -366,13 +387,18 @@ the MLFQS requirements. Demonstrate that your scheduling algorithm reduces response time relative to the original Pintos scheduling algorithm (round robin) for -at least one workload of your own design (i.e. in addition to the +at least one workload of your own design (i.e.@: in addition to the provided test). You may assume a static priority for this problem. It is not necessary to ``re-donate'' a thread's priority if it changes (although you are free to do so). +You must write your code so that we can turn the MLFQS on and off at +compile time. By default, it must be off, but we must be able to turn +it on by inserting the line @code{#define MLFQS 1} in +@file{constants.h}. @xref{Conditional Compilation}, for details. + @node Threads FAQ @section FAQ @@ -402,6 +428,13 @@ be truly temporary). There is no need to edit the @file{Makefile}s to add a @file{.h} file. +@item +@b{How do I write my test cases?} + +Test cases should be replacements for the existing @file{test.c} +file. Put them in a @file{threads/testcases} directory. +@xref{TESTCASE}, for more information. + @item @b{If a thread finishes, should its children be terminated immediately, or should they finish normally?} @@ -434,8 +467,11 @@ help you determine if you are using interrupts too haphazardly. We want to emphasize that there are only limited cases where this is appropriate. +You might find @file{devices/intq.h} and its users to be an +inspiration or source of rationale. + @item -@b{Where might interrupt-level manipuation be appropriate?} +@b{Where might interrupt-level manipulation be appropriate?} You might find it necessary in some solutions to the Alarm problem. @@ -509,7 +545,6 @@ gracefully and should act as a no-op. @b{Doesn't the priority scheduling lead to starvation? Or do I have to implement some sort of aging?} - It is true that strict priority scheduling can lead to starvation because thread may not run if a higher-priority thread is runnable. In this problem, don't worry about starvation or any sort of aging @@ -623,11 +658,10 @@ The correct behavior is to immediately yield the processor. Your solution must act this way. @item -@b{What range of priorities should be supported and what should the -default priority of a thread be?} +@b{What should @code{thread_get_priority()} return in a thread while +its priority has been increased by a donation?} -Your implementation should support priorities from 0 through 59 and -the default priority of a thread should be 29. +The higher (donated) priority. @end enumerate @item Advanced Scheduler FAQs @@ -640,6 +674,9 @@ Timer interrupts occur @code{TIMER_FREQ} times per second. You can adjust this value by editing @file{devices/timer.h}. The default is 100 Hz. +You can also adjust the number of timer ticks per time slice by +modifying @code{TIME_SLICE} in @file{devices/timer.c}. + @item @b{Do I have to modify the dispatch table?}