@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
+If the file system is compiled in, as it will be in project 2 and
later, we now initialize the disks with @func{disk_init}, then the
-filesystem with @func{filesys_init}, and run any operations that were
+file system with @func{filesys_init}, and run any operations that were
requested on the kernel command line with @func{fsutil_run}.
Boot is complete, so we print a message.
| magic |
| : |
| : |
- | name |
| status |
+ | tid |
0 kB +---------------------------------+
@end group
@end example
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}.
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
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