@end itemize
@item
-Problem 1-4 (MLFQS) builds on the features you
-implement in Problem 1-3. 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 1-3 fully working before you begin to tackle
-Problem 1-4.
+Problem 1-4 (MLFQS) builds on the features you implement in Problem
+1-3. You should have Problem 1-3 fully working before you begin to
+tackle Problem 1-4.
+
+@item
+In the past, many groups divided the assignment into pieces, then each
+group member worked on his or her piece until just before the
+deadline, at which time the group reconvened to combine their code and
+submit. @strong{This is a bad idea. We do not recommend this
+approach.} Groups that do this often find that two changes conflict
+with each other, requiring lots of last-minute debugging. Some groups
+who have done this have turned in code that did not even successfully
+boot.
+
+Instead, we recommend integrating your team's changes early and often,
+using a source code control system such as CVS (@pxref{CVS}) or a
+group collaboration site such as SourceForge (@pxref{SourceForge}).
+This is less likely to produce surprises, because everyone can see
+everyone else's code as it is written, instead of just when it is
+finished. These systems also make it possible to review changes and,
+when a change introduces a bug, drop back to working versions of code.
+
+@item
+You should expect to run into bugs that you simply don't understand
+while working on this and subsequent projects. When you do, go back
+and reread the appendix on debugging tools, which is filled with
+useful debugging tips that should help you to get back up to speed
+(@pxref{Debugging Tools}). Be sure to read the section on backtraces
+(@pxref{Backtraces}), which will help you to get the most out of every
+kernel panic or assertion failure.
@end itemize
@node Problem 1-1 Alarm Clock
first should return immediately.
Calling @func{thread_join} on an thread that is not the caller's
-child should cause the caller to return immediately.
+child should cause the caller to return immediately. For this purpose,
+children are not inherited, that is, if @var{A} has child @var{B} and
+@var{B} has child @var{C}, then @var{A} always returns immediately
+should it try to join @var{C}, even if @var{B} is dead.
Consider all the ways a join can occur: nested joins (@var{A} joins
@var{B}, then @var{B} joins @var{C}), multiple joins (@var{A} joins
if @func{thread_join} is called on a thread that has not yet been
scheduled for the first time? You should handle all of these cases.
Write test code that demonstrates the cases your join works for.
-Don't overdo the output volume, please!
Be careful to program this function correctly. You will need its
functionality for project 2.
immediately yield the processor to the new thread. Similarly, when
threads are waiting for a lock, semaphore or condition variable, the
highest priority waiting thread should be woken up first. A thread
-may set its priority at any time.
+may raise or lower its own priority at any time, but lowering its
+priority such that it no longer has the highest priority must cause it
+to immediately yield the CPU.
One issue with priority scheduling is ``priority inversion'': if a
high priority thread needs to wait for a low priority thread (for
although you are welcome to do so. However, you do need to implement
priority scheduling in all cases.
-You may assume a static priority for priority donation, that is, it is
-not necessary to ``re-donate'' a thread's priority if it changes
-(although you are free to do so).
-
@node Problem 1-4 Advanced Scheduler
@section Problem 1-4: Advanced Scheduler