X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=doc%2Ftour.texi;h=81eb5bd8786941cedf22ecd66b43e6915a70d922;hb=2cfc156c39840ce7f1cda6b473de1322691a8a0b;hp=ee90cca0f55d22b0896bcc144a35416624655a8f;hpb=1e70978fdf2e3dd9a3c2153dab259bc689fd7d31;p=pintos-anon diff --git a/doc/tour.texi b/doc/tour.texi index ee90cca..81eb5bd 100644 --- a/doc/tour.texi +++ b/doc/tour.texi @@ -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 (¬_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 @@ -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