Fix condition variable example.
[pintos-anon] / doc / tour.texi
index ee90cca0f55d22b0896bcc144a35416624655a8f..d9dab057a06f88dab97099d32ef16f98badcf2fb 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
 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
 
 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
@@ -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
 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
 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
 
 @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
 
 @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
 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}.
 
 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
 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.
 
 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
 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
 
 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);
 
 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++;
   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);
   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--;
   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
   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
 @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
 
 @item
 @dfn{Internal interrupts}, that is, interrupts caused by something