Add PC speaker driver and connect it to '\a' in the VGA console.
[pintos-anon] / doc / threads.texi
index 2f42e3dc5979b8f8ab33fd79db7af020a285c932..d90b43895396a0ec81c3ff9c4ae91515572522ac 100644 (file)
@@ -1,4 +1,4 @@
-@node Project 1--Threads, Project 2--User Programs, Pintos Tour, Top
+@node Project 1--Threads
 @chapter Project 1: Threads
 
 In this assignment, we give you a minimally functional thread system.
@@ -12,9 +12,9 @@ side.  Compilation should be done in the @file{threads} directory.
 Before you read the description of this project, you should read all of
 the following sections: @ref{Introduction}, @ref{Coding Standards},
 @ref{Debugging Tools}, and @ref{Development Tools}.  You should at least
-skim the material in @ref{Threads Tour} and especially
-@ref{Synchronization}.  To complete this project you will also need to
-read @ref{4.4BSD Scheduler}.
+skim the material from @ref{Pintos Loading} through @ref{Memory
+Allocation}, especially @ref{Synchronization}.  To complete this project
+you will also need to read @ref{4.4BSD Scheduler}.
 
 @menu
 * Project 1 Background::        
@@ -40,7 +40,7 @@ The first step is to read and understand the code for the initial thread
 system.
 Pintos already implements thread creation and thread completion,
 a simple scheduler to switch between threads, and synchronization
-primitives (semaphores, locks, condition variables, and memory
+primitives (semaphores, locks, condition variables, and optimization
 barriers).
 
 Some of this code might seem slightly mysterious.  If
@@ -76,11 +76,11 @@ assembly code.  (You don't have to understand it.)  It saves the
 state of the currently running thread and restores the state of the
 thread we're switching to.
 
-Using the @command{gdb} debugger, slowly trace through a context
-switch to see what happens (@pxref{gdb}).  You can set a
+Using the GDB debugger, slowly trace through a context
+switch to see what happens (@pxref{GDB}).  You can set a
 breakpoint on @func{schedule} to start out, and then
-single-step from there.@footnote{@command{gdb} might tell you that
-@func{schedule} doesn't exist, which is arguably a @command{gdb} bug.
+single-step from there.@footnote{GDB might tell you that
+@func{schedule} doesn't exist, which is arguably a GDB bug.
 You can work around this by setting the breakpoint by filename and
 line number, e.g.@: @code{break thread.c:@var{ln}} where @var{ln} is
 the line number of the first declaration in @func{schedule}.}  Be sure
@@ -137,10 +137,10 @@ here.  @xref{Kernel Initialization}, for details.
 
 @item thread.c
 @itemx thread.h
-Basic thread support.  Much of your work will take place in these
-files.  @file{thread.h} defines @struct{thread}, which you are likely
-to modify in all four projects.  See @ref{struct thread} and @ref{Thread
-Support} for more information.
+Basic thread support.  Much of your work will take place in these files.
+@file{thread.h} defines @struct{thread}, which you are likely to modify
+in all four projects.  See @ref{struct thread} and @ref{Threads} for
+more information.
 
 @item switch.S
 @itemx switch.h
@@ -170,7 +170,7 @@ Infrastructure}, for more information.
 @item synch.c
 @itemx synch.h
 Basic synchronization primitives: semaphores, locks, condition
-variables, and memory barriers.  You will need to use these for
+variables, and optimization barriers.  You will need to use these for
 synchronization in all
 four projects.  @xref{Synchronization}, for more information.
 
@@ -178,15 +178,16 @@ four projects.  @xref{Synchronization}, for more information.
 Functions for I/O port access.  This is mostly used by source code in
 the @file{devices} directory that you won't have to touch.
 
-@item mmu.h
-Functions and macros related to memory management, including page
-directories and page tables.  This will be more important to you in
-project 3.  For now, you can ignore it.
+@item vaddr.h
+@itemx pte.h
+Functions and macros for working with virtual addresses and page table
+entries.  These will be more important to you in project 3.  For now,
+you can ignore them.
 
 @item flags.h
 Macros that define a few bits in the 80@var{x}86 ``flags'' register.
-Probably of no interest.  See @bibref{IA32-v1}, section 3.4.3, for more
-information.
+Probably of no interest.  See @bibref{IA32-v1}, section 3.4.3, ``EFLAGS
+Register,'' for more information.
 @end table
 
 @menu
@@ -216,19 +217,45 @@ call this code yourself.
 @item serial.c
 @itemx serial.h
 Serial port driver.  Again, @func{printf} calls this code for you,
-so you don't need to do so yourself.  Feel free to look through it if
-you're curious.
+so you don't need to do so yourself.
+It handles serial input by passing it to the input layer (see below).
 
 @item disk.c
 @itemx disk.h
 Supports reading and writing sectors on up to 4 IDE disks.  This won't
 actually be used until project 2.
 
+@item kbd.c
+@itemx kbd.h
+Keyboard driver.  Handles keystrokes passing them to the input layer
+(see below).
+
+@item input.c
+@itemx input.h
+Input layer.  Queues input characters passed along by the keyboard or
+serial drivers.
+
 @item intq.c
 @itemx intq.h
 Interrupt queue, for managing a circular queue that both kernel
 threads and interrupt handlers want to access.  Used by the keyboard
 and serial drivers.
+
+@item rtc.c
+@itemx rtc.h
+Real-time clock driver, to enable the kernel to determine the current
+date and time.  By default, this is only used by @file{thread/init.c}
+to choose an initial seed for the random number generator.
+
+@item speaker.c
+@itemx speaker.h
+Driver that can produce tones on the PC speaker.
+
+@item pit.c
+@itemx pit.h
+Code to configure the 8254 Programmable Interrupt Timer.  This code is
+used by both @file{devices/timer.c} and @file{devices/speaker.c}
+because each device uses one of the PIT's output channel.
 @end table
 
 @node lib files
@@ -266,7 +293,11 @@ more information.
 
 @item random.c
 @itemx random.h
-Pseudo-random number generator.
+Pseudo-random number generator.  The actual sequence of random values
+will not vary from one Pintos run to another, unless you do one of
+three things: specify a new random seed value on the @option{-rs}
+kernel command-line option on each run, or use a simulator other than
+Bochs, or specify the @option{-r} option to @command{pintos}.
 
 @item round.h
 Macros for rounding.
@@ -328,9 +359,15 @@ timer ticks or input events.  Turning off interrupts also increases the
 interrupt handling latency, which can make a machine feel sluggish if
 taken too far.
 
+The synchronization primitives themselves in @file{synch.c} are
+implemented by disabling interrupts.  You may need to increase the
+amount of code that runs with interrupts disabled here, but you should
+still try to keep it to a minimum.
+
 Disabling interrupts can be useful for debugging, if you want to make
 sure that a section of code is not interrupted.  You should remove
-debugging code before turning in your project.
+debugging code before turning in your project.  (Don't just comment it
+out, because that can make the code difficult to read.)
 
 There should be no busy waiting in your submission.  A tight loop that
 calls @func{thread_yield} is one form of busy waiting.
@@ -347,13 +384,7 @@ with each other, requiring lots of last-minute debugging.  Some groups
 who have done this have turned in code that did not even compile or
 boot, much less pass any tests.
 
-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.
+@localcvspolicy{}
 
 You should expect to run into bugs that you simply don't understand
 while working on this and subsequent projects.  When you do,
@@ -430,14 +461,14 @@ 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
 threads are waiting for a lock, semaphore, or condition variable, the
-highest priority waiting thread should be woken up first.  A thread
+highest priority waiting thread should be awakened first.  A thread
 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.
 
 Thread priorities range from @code{PRI_MIN} (0) to @code{PRI_MAX} (63).
-Lower numbers correspond to @emph{higher} priorities, so that priority 0
-is the highest priority and priority 63 is the lowest.
+Lower numbers correspond to lower priorities, so that priority 0
+is the lowest priority and priority 63 is the highest.
 The initial thread priority is passed as an argument to
 @func{thread_create}.  If there's no reason to choose another
 priority, use @code{PRI_DEFAULT} (31).  The @code{PRI_} macros are
@@ -459,12 +490,13 @@ multiple donations, in which multiple priorities are donated to a single
 thread.  You must also handle nested donation: if @var{H} is waiting on
 a lock that @var{M} holds and @var{M} is waiting on a lock that @var{L}
 holds, then both @var{M} and @var{L} should be boosted to @var{H}'s
-priority.
+priority.  If necessary, you may impose a reasonable limit on depth of
+nested priority donation, such as 8 levels.
 
 You must implement priority donation for locks.  You need not
-implement priority donation for semaphores or condition variables
-(but you are welcome to do so).  You do need to implement
-priority scheduling in all cases.
+implement priority donation for the other Pintos synchronization
+constructs.  You do need to implement priority scheduling in all
+cases.
 
 Finally, implement the following functions that allow a thread to
 examine and modify its own priority.  Skeletons for these functions are
@@ -491,20 +523,22 @@ The priority scheduler is not used in any later project.
 Implement a multilevel feedback queue scheduler similar to the
 4.4@acronym{BSD} scheduler to
 reduce the average response time for running jobs on your system.
-@xref{4.4BSD Scheduler}, for a detailed description of
-the MLFQS requirements.
+@xref{4.4BSD Scheduler}, for detailed requirements.
 
-The advanced scheduler builds on the priority scheduler.  You should
-have the priority scheduler working, except possibly for priority
-donation, before you start work on the advanced scheduler.
+Like the priority scheduler, the advanced scheduler chooses the thread
+to run based on priorities.  However, the advanced scheduler does not do
+priority donation.  Thus, we recommend that you have the priority
+scheduler working, except possibly for priority donation, before you
+start work on the advanced scheduler.
 
-You must write your code so that we can choose a scheduling algorithm
-policy at Pintos startup time.  By default, the round-robin scheduler
+You must write your code to allow us to choose a scheduling algorithm
+policy at Pintos startup time.  By default, the priority scheduler
 must be active, but we must be able to choose the 4.4@acronym{BSD}
 scheduler
 with the @option{-mlfqs} kernel option.  Passing this
-option sets @code{enable_mlfqs}, declared in @file{threads/init.h}, to
-true.
+option sets @code{thread_mlfqs}, declared in @file{threads/thread.h}, to
+true when the options are parsed by @func{parse_options}, which happens
+early in @func{main}.
 
 When the 4.4@acronym{BSD} scheduler is enabled, threads no longer
 directly control their own priorities.  The @var{priority} argument to
@@ -524,6 +558,12 @@ Here's a summary of our reference solution, produced by the
 @command{diffstat} program.  The final row gives total lines inserted
 and deleted; a changed line counts as both an insertion and a deletion.
 
+The reference solution represents just one possible solution.  Many
+other solutions are also possible and many of those differ greatly from
+the reference solution.  Some excellent solutions may not modify all the
+files modified by the reference solution, and some may modify files not
+modified by the reference solution.
+
 @verbatim
  devices/timer.c       |   42 +++++-
  threads/fixed-point.h |  120 ++++++++++++++++++
@@ -533,6 +573,8 @@ and deleted; a changed line counts as both an insertion and a deletion.
  5 files changed, 440 insertions(+), 29 deletions(-)
 @end verbatim
 
+@file{fixed-point.h} is a new file added by the reference solution.
+
 @item How do I update the @file{Makefile}s when I add a new source file?
 
 @anchor{Adding Source Files}
@@ -578,8 +620,79 @@ to cause many of the tests to fail.
 There are @code{TIME_SLICE} ticks per time slice.  This macro is
 declared in @file{threads/thread.c}.  The default is 4 ticks.
 
-We don't recommend changing this values, because any changes are likely
+We don't recommend changing this value, because any changes are likely
 to cause many of the tests to fail.
+
+@item How do I run the tests?
+
+@xref{Testing}.
+
+@item Why do I get a test failure in @func{pass}?
+
+@anchor{The pass function fails}
+You are probably looking at a backtrace that looks something like this:
+
+@example
+0xc0108810: debug_panic (lib/kernel/debug.c:32)
+0xc010a99f: pass (tests/threads/tests.c:93)
+0xc010bdd3: test_mlfqs_load_1 (...threads/mlfqs-load-1.c:33)
+0xc010a8cf: run_test (tests/threads/tests.c:51)
+0xc0100452: run_task (threads/init.c:283)
+0xc0100536: run_actions (threads/init.c:333)
+0xc01000bb: main (threads/init.c:137)
+@end example
+
+This is just confusing output from the @command{backtrace} program.  It
+does not actually mean that @func{pass} called @func{debug_panic}.  In
+fact, @func{fail} called @func{debug_panic} (via the @func{PANIC}
+macro).  GCC knows that @func{debug_panic} does not return, because it
+is declared @code{NO_RETURN} (@pxref{Function and Parameter
+Attributes}), so it doesn't include any code in @func{fail} to take
+control when @func{debug_panic} returns.  This means that the return
+address on the stack looks like it is at the beginning of the function
+that happens to follow @func{fail} in memory, which in this case happens
+to be @func{pass}.
+
+@xref{Backtraces}, for more information.
+
+@item How do interrupts get re-enabled in the new thread following @func{schedule}?
+
+Every path into @func{schedule} disables interrupts.  They eventually
+get re-enabled by the next thread to be scheduled.  Consider the
+possibilities: the new thread is running in @func{switch_thread} (but
+see below), which is called by @func{schedule}, which is called by one
+of a few possible functions:
+
+@itemize @bullet
+@item
+@func{thread_exit}, but we'll never switch back into such a thread, so
+it's uninteresting.
+
+@item
+@func{thread_yield}, which immediately restores the interrupt level upon
+return from @func{schedule}.
+
+@item
+@func{thread_block}, which is called from multiple places:
+
+@itemize @minus
+@item
+@func{sema_down}, which restores the interrupt level before returning.
+
+@item
+@func{idle}, which enables interrupts with an explicit assembly STI
+instruction.
+
+@item
+@func{wait} in @file{devices/intq.c}, whose callers are responsible for
+re-enabling interrupts.
+@end itemize
+@end itemize
+
+There is a special case when a newly created thread runs for the first
+time.  Such a thread calls @func{intr_enable} as the first action in
+@func{kernel_thread}, which is at the bottom of the call stack for every
+kernel thread but the first.
 @end table
 
 @menu
@@ -597,7 +710,7 @@ to cause many of the tests to fail.
 Don't worry about the possibility of timer values overflowing.  Timer
 values are expressed as signed 64-bit numbers, which at 100 ticks per
 second should be good for almost 2,924,712,087 years.  By then, we
-expect Pintos to have been phased out of the CS 140 curriculum.
+expect Pintos to have been phased out of the @value{coursenumber} curriculum.
 @end table
 
 @node Priority Scheduling FAQ
@@ -626,7 +739,7 @@ list.
 
 @item If the highest-priority thread yields, does it continue running?
 
-Yes.  As long as there is a single highest-priority thread, it continues
+Yes.  If there is a single highest-priority thread, it continues
 running until it blocks or finishes, even if it calls
 @func{thread_yield}.
 If multiple threads have the same highest priority,
@@ -641,11 +754,16 @@ to thread @var{B} (with priority 3), then @var{B}'s new priority is 5, not 8.
 
 @item Can a thread's priority change while it is on the ready queue?
 
-Yes.  Consider this case: low-priority thread @var{L} holds a
-lock that high-priority thread @var{H} wants, so @var{H} donates its
-priority to @var{L}.  @var{L} releases the lock and
-thus loses the CPU and is moved to the ready queue.  Now @var{L}'s
-old priority is restored while it is in the ready queue.
+Yes.  Consider a ready, low-priority thread @var{L} that holds a lock.
+High-priority thread @var{H} attempts to acquire the lock and blocks,
+thereby donating its priority to ready thread @var{L}.
+
+@item Can a thread's priority change while it is blocked?
+
+Yes.  While a thread that has acquired lock @var{L} is blocked for any
+reason, its priority can increase by priority donation if a
+higher-priority thread attempts to acquire @var{L}.  This case is
+checked by the @code{priority-donate-sema} test.
 
 @item Can a thread added to the ready list preempt the processor?
 
@@ -657,17 +775,41 @@ preempting whatever thread is currently running.
 
 @item How does @func{thread_set_priority} affect a thread receiving donations?
 
-It should do something sensible, but no particular behavior is
-required.  None of the test cases call @func{thread_set_priority} from a
-thread while it is receiving a priority donation.
-
-@item Calling @func{printf} in @func{sema_up} or @func{sema_down} reboots!
-
-@anchor{printf Reboots}
-Yes.  These functions are called before @func{printf} is ready to go.
-You could add a global flag initialized to false and set it to true
-just before the first @func{printf} in @func{main}.  Then modify
-@func{printf} itself to return immediately if the flag isn't set.
+It sets the thread's base priority.  The thread's effective priority
+becomes the higher of the newly set priority or the highest donated
+priority.  When the donations are released, the thread's priority
+becomes the one set through the function call.  This behavior is checked
+by the @code{priority-donate-lower} test.
+
+@item Doubled test names in output make them fail.
+
+Suppose you are seeing output in which some test names are doubled,
+like this:
+
+@example
+(alarm-priority) begin
+(alarm-priority) (alarm-priority) Thread priority 30 woke up.
+Thread priority 29 woke up.
+(alarm-priority) Thread priority 28 woke up.
+@end example
+
+What is happening is that output from two threads is being
+interleaved.  That is, one thread is printing @code{"(alarm-priority)
+Thread priority 29 woke up.\n"} and another thread is printing
+@code{"(alarm-priority) Thread priority 30 woke up.\n"}, but the first
+thread is being preempted by the second in the middle of its output.
+
+This problem indicates a bug in your priority scheduler.  After all, a
+thread with priority 29 should not be able to run while a thread with
+priority 30 has work to do.
+
+Normally, the implementation of the @code{printf()} function in the
+Pintos kernel attempts to prevent such interleaved output by acquiring
+a console lock during the duration of the @code{printf} call and
+releasing it afterwards.  However, the output of the test name,
+e.g., @code{(alarm-priority)}, and the message following it is output
+using two calls to @code{printf}, resulting in the console lock being
+acquired and released twice.
 @end table
 
 @node Advanced Scheduler FAQ
@@ -678,4 +820,37 @@ just before the first @func{printf} in @func{main}.  Then modify
 
 It doesn't have to.  We won't test priority donation and the advanced
 scheduler at the same time.
+
+@item Can I use one queue instead of 64 queues?
+
+Yes.  In general, your implementation may differ from the description,
+as long as its behavior is the same.
+
+@item Some scheduler tests fail and I don't understand why.  Help!
+
+If your implementation mysteriously fails some of the advanced
+scheduler tests, try the following:
+
+@itemize
+@item
+Read the source files for the tests that you're failing, to make sure
+that you understand what's going on.  Each one has a comment at the
+top that explains its purpose and expected results.
+
+@item
+Double-check your fixed-point arithmetic routines and your use of them
+in the scheduler routines.
+
+@item
+Consider how much work your implementation does in the timer
+interrupt.  If the timer interrupt handler takes too long, then it
+will take away most of a timer tick from the thread that the timer
+interrupt preempted.  When it returns control to that thread, it
+therefore won't get to do much work before the next timer interrupt
+arrives.  That thread will therefore get blamed for a lot more CPU
+time than it actually got a chance to use.  This raises the
+interrupted thread's recent CPU count, thereby lowering its priority.
+It can cause scheduling decisions to change.  It also raises the load
+average.
+@end itemize
 @end table