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
| magic |
| : |
| : |
- | name |
| status |
+ | tid |
0 kB +---------------------------------+
@end group
@end example
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
@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
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}.
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.
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
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 (¬_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 (¬_full, &lock);
+ buf[head++ % BUF_SIZE] = ch; /* @r{Add @var{ch} to @var{buf}.} */
n++;
- cond_signal (¬_empty); /* @r{@var{buf} can't be empty anymore.} */
+ cond_signal (¬_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 (¬_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 (¬_empty, &lock);
+ ch = buf[tail++ % BUF_SIZE]; /* @r{Get @var{ch} from @var{buf}.} */
n--;
- cond_signal (¬_full); /* @r{@var{buf} can't be full anymore.} */
+ cond_signal (¬_full, &lock); /* @r{@var{buf} can't be full anymore.} */
lock_release (&lock);
@}
@end example
@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