Move problem 1-2 (join) into project 2 as the "wait" system call.
[pintos-anon] / doc / tour.texi
index ee90cca0f55d22b0896bcc144a35416624655a8f..81eb5bd8786941cedf22ecd66b43e6915a70d922 100644 (file)
@@ -173,7 +173,8 @@ and @func{syscall_init}.
 Now that interrupts are set up, we can start preemptively scheduling
 threads with @func{thread_start}, which also enables interrupts.
 Interrupt-driven serial port I/O is also possible now, so we use
-@func{serial_init_queue} to switch to that mode.
+@func{serial_init_queue} to switch to that mode.  Finally,
+@func{timer_calibrate} calibrates the timer for accurate short delays.
 
 If the filesystem is compiled in, as it will be in project 2 and
 later, we now initialize the disks with @func{disk_init}, then the
@@ -260,10 +261,10 @@ other registers that must be saved are saved on the stack.
 A thread priority, ranging from the lowest possible priority
 @code{PRI_MIN} (0) to the highest possible priority @code{PRI_MAX}
 (59).  Pintos as provided ignores thread priorities, but you will
-implement priority scheduling in problem 1-3 (@pxref{Problem 1-3
+implement priority scheduling in problem 1-2 (@pxref{Problem 1-2
 Priority Scheduling}).
 
-@item list_elem elem;
+@item struct list_elem elem;
 A ``list element'' used to put the thread into doubly linked lists,
 either the list of threads ready to run or a list of threads waiting
 on a semaphore.  Take a look at @file{lib/kernel/list.h} for
@@ -302,8 +303,8 @@ grows downward from the end of the page.  It looks like this:
              |              magic              |
              |                :                |
              |                :                |
-             |               name              |
              |              status             |
+             |               tid               |
         0 kB +---------------------------------+
 @end group
 @end example
@@ -494,7 +495,7 @@ is, kernel threads can be preempted at any time.  Traditional Unix
 systems are ``nonpreemptible,'' that is, kernel threads can only be
 preempted at points where they explicitly call into the scheduler.
 User programs can be preempted at any time in both models.  As you
-might imagine, preemptible kernels require more use of
+might imagine, preemptible kernels require more explicit
 synchronization.
 
 You should have little need to set the interrupt state directly.  Most
@@ -529,8 +530,8 @@ Turns interrupts off and returns the previous interrupt state.
 @node Semaphores
 @subsubsection Semaphores
 
-A semaphore is a nonnegative integer along with two atomic operators
-for manipulating it, which are:
+A semaphore is a nonnegative integer along with two operators
+for atomically manipulating it, which are:
 
 @itemize @bullet
 @item
@@ -552,8 +553,10 @@ A semaphore initialized to 0 can be useful for waiting for an event
 that will happen exactly once.  For example, suppose thread @var{A}
 starts another thread @var{B} and wants to wait for @var{B} to signal
 that some activity is complete.  @var{A} can create a semaphore
-initialized to 0, pass it to @var{B}, and then ``down'' the semaphore.
-When @var{B} finishes its activity, it ``ups'' the semaphore.
+initialized to 0, pass it to @var{B} as it starts it, and then
+``down'' the semaphore.  When @var{B} finishes its activity, it
+``ups'' the semaphore.  This works regardless of whether @var{A}
+``downs'' the semaphore or @var{B} ``ups'' it first.
 
 Pintos declared its semaphore type and operations on them in
 @file{threads/synch.h}.
@@ -593,7 +596,7 @@ semaphore is twofold.  First, a semaphore can have a value greater
 than 1, but a lock can only be owned by a single thread at a time.
 Second, a semaphore does not have an owner, meaning that one thread
 can ``down'' the semaphore and then another one ``up'' it, but with a
-lock the same thread must both acquire and release it.  When these
+lock a single thread must both acquire and release it.  When these
 restrictions prove onerous, it's a good sign that a semaphore should
 be used, instead of a lock.
 
@@ -632,8 +635,8 @@ A condition variable allows one piece of code to signal a condition
 and cooperating code to receive the signal and act upon it.  Each
 condition variable is associated with a lock.  A given condition
 variable is associated with only a single lock, but one lock may be
-associated with any number of condition variables.  A lock along with
-all of its condition variables is known as a ``monitor.''
+associated with any number of condition variables.  A set of condition
+variables taken together with their lock is called a ``monitor.''
 
 A thread that owns the monitor lock is said to be ``in the monitor.''
 The thread in the monitor has control over all the data protected with
@@ -664,22 +667,22 @@ struct condition not_full; /* @r{Signaled when the buffer is not full.} */
 
 void put (char ch) @{
   lock_acquire (&lock);
-  while (n == BUF_SIZE)         /* @r{Can't add to @var{buf} as long as it's full.} */
-    cond_wait (&not_full);
-  buf[head++ % BUF_SIZE] = ch;  /* @r{Add @var{ch} to @var{buf}.} */
+  while (n == BUF_SIZE)            /* @r{Can't add to @var{buf} as long as it's full.} */
+    cond_wait (&not_full, &lock);
+  buf[head++ % BUF_SIZE] = ch;     /* @r{Add @var{ch} to @var{buf}.} */
   n++;
-  cond_signal (&not_empty);     /* @r{@var{buf} can't be empty anymore.} */
+  cond_signal (&not_empty, &lock); /* @r{@var{buf} can't be empty anymore.} */
   lock_release (&lock);
 @}
 
 char get (void) @{
   char ch;
   lock_acquire (&lock);
-  while (n == 0)                /* @r{Can't read from @var{buf} as long as it's empty.} */
-    cond_wait (&not_empty);
-  ch = buf[tail++ % BUF_SIZE];  /* @r{Get @var{ch} from @var{buf}.} */
+  while (n == 0)                  /* @r{Can't read from @var{buf} as long as it's empty.} */
+    cond_wait (&not_empty, &lock);
+  ch = buf[tail++ % BUF_SIZE];    /* @r{Get @var{ch} from @var{buf}.} */
   n--;
-  cond_signal (&not_full);      /* @r{@var{buf} can't be full anymore.} */
+  cond_signal (&not_full, &lock); /* @r{@var{buf} can't be full anymore.} */
   lock_release (&lock);
 @}
 @end example
@@ -735,7 +738,7 @@ timer, keyboard, serial ports, and disks.  External interrupts are
 @dfn{asynchronous}, meaning that they don't occur in a fashion
 synchronized with anything going on in the CPU.  External interrupts
 are what @func{intr_disable} and related functions can arrange to
-temporarily ignore (@pxref{Disabling Interrupts}).
+postpone (@pxref{Disabling Interrupts}).
 
 @item
 @dfn{Internal interrupts}, that is, interrupts caused by something
@@ -779,11 +782,7 @@ In Pintos, @func{intr_init} in @file{threads/interrupt.c} sets up the
 IDT so that each entry points to a unique entry point in
 @file{threads/intr-stubs.S} named @func{intr@var{NN}_stub}, where
 @var{NN} is the interrupt number in
-hexadecimal.@footnote{@file{threads/intr-stubs.S} is so repetitive
-that it is actually generated by a Perl script,
-@file{threads/intr-stubs.pl}.  Thus, you will actually find
-@file{threads/intr-stubs.S} in your @file{threads/build/threads}
-directory, not in plain @file{threads}.}  Because the CPU doesn't give
+hexadecimal.  Because the CPU doesn't give
 us any other way to find out the interrupt number, this entry point
 pushes the interrupt number on the stack.  Then it jumps to
 @func{intr_entry}, which pushes all the registers that the processor