Update docs.
[pintos-anon] / doc / tour.texi
index abbcb692b1f5f0e1b2890a7453d7beea762ecad6..41fde25ae08c6b163e1d7118486e5540b8a412b3 100644 (file)
@@ -1,4 +1,4 @@
-@node Pintos Tour
+@node Pintos Tour, Project 1--Threads, Introduction, Top
 @chapter A Tour Through Pintos
 
 This chapter is a brief tour through the Pintos code.  It covers the
 @chapter A Tour Through Pintos
 
 This chapter is a brief tour through the Pintos code.  It covers the
@@ -6,12 +6,25 @@ entire code base, but you'll only be using Pintos one part at a time,
 so you may find that you want to read each part as you work on the
 corresponding project.
 
 so you may find that you want to read each part as you work on the
 corresponding project.
 
+Hint: try using ``tags'' to follow along with references to function
+and variable names (@pxref{Tags}).
+
+@menu
+* Pintos Loading::              
+* Threads Tour::                
+@end menu
+
 @node Pintos Loading
 @section Loading
 
 This section covers the Pintos loader and basic kernel
 initialization.
 
 @node Pintos Loading
 @section Loading
 
 This section covers the Pintos loader and basic kernel
 initialization.
 
+@menu
+* Pintos Loader::               
+* Kernel Initialization::       
+@end menu
+
 @node Pintos Loader
 @subsection The Loader
 
 @node Pintos Loader
 @subsection The Loader
 
@@ -77,7 +90,7 @@ Then we jump to the start of the compiled kernel image.  Using the
 ``linker script'' in @file{threads/kernel.lds.S}, the kernel has
 arranged that it begins with the assembly module
 @file{threads/start.S}.  This assembly module just calls
 ``linker script'' in @file{threads/kernel.lds.S}, the kernel has
 arranged that it begins with the assembly module
 @file{threads/start.S}.  This assembly module just calls
-@code{main()}, which never returns.
+@func{main}, which never returns.
 
 There's one more trick to the loader: the Pintos kernel command line
 is stored in the boot loader.  The @command{pintos} program actually
 
 There's one more trick to the loader: the Pintos kernel command line
 is stored in the boot loader.  The @command{pintos} program actually
@@ -90,18 +103,20 @@ and effective.
 @node Kernel Initialization
 @subsection Kernel Initialization
 
 @node Kernel Initialization
 @subsection Kernel Initialization
 
-The kernel proper starts with the @code{main()} function.  The
-@code{main()} function is written in C, as will be most of the code we
+The kernel proper starts with the @func{main} function.  The
+@func{main} function is written in C, as will be most of the code we
 encounter in Pintos from here on out.
 
 encounter in Pintos from here on out.
 
-When @code{main()} starts, the system is in a pretty raw state.  We're
+When @func{main} starts, the system is in a pretty raw state.  We're
 in protected mode with paging enabled, but hardly anything else is
 in protected mode with paging enabled, but hardly anything else is
-ready.  Thus, the @code{main()} function consists primarily of calls
-into other Pintos modules' initialization functions, which are
-typically named @code{@var{module}_init()}, where @var{module} is the
-module's name.
+ready.  Thus, the @func{main} function consists primarily of calls
+into other Pintos modules' initialization functions.  You should
+notice that these are usually named @func{@var{module}_init}, where
+@var{module} is the module's name, @file{@var{module}.c} is the
+module's source code, and @file{@var{module}.h} is the module's
+header.
 
 
-First we initialize kernel RAM in @code{ram_init()}.  The first step
+First we initialize kernel RAM in @func{ram_init}.  The first step
 is to clear out the kernel's so-called ``BSS'' segment.  The BSS is a
 segment that should be initialized to all zeros.  In C, whenever you
 declare a variable outside a function without providing an
 is to clear out the kernel's so-called ``BSS'' segment.  The BSS is a
 segment that should be initialized to all zeros.  In C, whenever you
 declare a variable outside a function without providing an
@@ -109,12 +124,248 @@ initializer, that variable goes into the BSS.@footnote{This isn't
 actually required by the ANSI C standard, but it is the case with most
 implementations of C on most machines.}  Because it's all zeros, the
 BSS isn't stored in the image that the loader brought into memory.  We
 actually required by the ANSI C standard, but it is the case with most
 implementations of C on most machines.}  Because it's all zeros, the
 BSS isn't stored in the image that the loader brought into memory.  We
-just use @code{memset()} to zero it out.  The other task of
-@code{ram_init()} is to read out the machine's memory size from where
+just use @func{memset} to zero it out.  The other task of
+@func{ram_init} is to read out the machine's memory size from where
 the loader stored it and put it into the @code{ram_pages} variable for
 later use.
 
 the loader stored it and put it into the @code{ram_pages} variable for
 later use.
 
+Next, @func{thread_init} initializes the thread system.  We will defer
+full discussion to our discussion of Pintos threads below.  It is
+called so early in initialization because the console, initialized
+just below, tries to use locks and locks in turn require there to be a
+running thread.
+
+Then we initialize the console so that we can use @func{printf}.
+@func{main} calls @func{vga_init}, which initializes the VGA text
+display and clears the screen.  It also calls @func{serial_init_poll}
+to initialize the first serial port in ``polling mode,'' that is,
+where the kernel busy-waits for the port to be ready for each
+character to be output.  (We use polling mode until we're ready to set
+up interrupts later.)  Finally we initialize the console device and
+print a startup message to the console.
+
+@func{main} calls @func{argv_init} to parse the kernel command line.
+This entails reading the command line out of the loader and updating
+global variables appropriately.
+
+The next block of functions we call initialize the kernel's memory
+system.  @func{palloc_init} sets up the kernel page allocator, which
+doles out memory one or more pages at a time.  @func{malloc_init} sets
+up the allocator that handles odd-sized allocations.
+@func{paging_init} sets up a page table for the kernel.
+
+In projects 2 and later, @func{main} also calls @func{tss_init} and
+@func{gdt_init}, but we'll talk about those later.
+
+@func{main} calls @func{random_init} to initialize the kernel random
+number generator.  @func{argv_init} might already have done this (if
+the user specified @option{-rs} on the @command{pintos} command line)
+but calling it a second time is harmless and has no effect.
+
+We initialize the interrupt system in the next set of calls.
+@func{intr_init} sets up the CPU's @dfn{interrupt descriptor table}
+(IDT) to ready it for interrupt handling, then @func{timer_init} and
+@func{kbd_init} prepare us to handle timer interrupts and keyboard
+interrupts, respectively.  In projects 2 and later, we also prepare to
+handle interrupts caused by user programs using @func{exception_init}
+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.
+
+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
+filesystem 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.
+
+For project 1, now we execute @func{test}, which runs whatever test is
+currently compiled into the kernel.  For later projects, we will
+instead run a user program and wait for it to complete.
+
+Finally, if @option{-q} was specified on the kernel command line, we
+call @func{power_off} to terminate the machine simulator.  Otherwise,
+@func{main} calls @func{thread_exit}, which allows any other running
+threads to continue running.
 
 @node Threads Tour
 @section Threads
 
 @node Threads Tour
 @section Threads
+
+@menu
+* struct thread::               
+@end menu
+
+@node struct thread
+@subsection @struct{thread}
+
+The main Pintos data structure for threads is @struct{thread},
+declared in @file{threads/thread.h}.  @struct{thread} has these
+members with the given type:
+
+@table @code
+@item tid_t tid;
+The thread's thread identifier or @dfn{tid}.  Every thread must have a
+tid that is unique over the entire lifetime of the kernel.  By
+default, @code{tid_t} is a @code{typedef} for @code{int} and each new
+thread receives the numerically next higher tid, starting from 1 for
+the initial process.  You can change the type and the numbering scheme
+if you like.
+
+@item enum thread_status status;
+The thread's state, one of these:
+
+@table @code
+@item THREAD_RUNNING
+The thread is running.  Exactly one thread is running at a given time.
+@func{thread_current} returns the running thread.
+
+@item THREAD_READY
+The thread is ready to run, but it's not running right now.  The
+thread could be selected to run the next time the scheduler is
+invoked.  Ready threads are kept in a doubly linked list called
+@code{ready_list}.
+
+@item THREAD_BLOCKED
+The thread is waiting for something, e.g.@: a lock to become
+available, an interrupt to be invoked.  The thread won't be scheduled
+again until it transitions to the @code{THREAD_READY} state with a
+call to @func{thread_unblock}.
+
+@item THREAD_DYING
+The thread will be destroyed by the scheduler after switching to the
+next thread.
+@end table
+
+@item char name[16];
+The thread's name as a string, or at least the first few characters of
+it.
+
+@item uint8_t *stack;
+Every thread has its own stack to keep track of its state.  When the
+thread is running, the CPU's stack pointer register tracks the top of
+the stack and this member is unused.  But when the CPU switches to
+another thread, this member saves the thread's stack pointer.  No
+other members are needed to save the thread's registers, because the
+other registers that must be saved are saved on the stack.
+
+@item int priority;
+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
+Priority Scheduling}).
+
+@item 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
+information on how to use the Pintos doubly linked list ADT.
+
+@item uint32_t *pagedir;
+Only present in project 2 and later.
+
+@item unsigned magic;
+Always set to @code{THREAD_MAGIC}, which is just a random number
+defined in @file{threads/thread.c}, and used to detect stack overflow.
+See below for more information.
+@end table
+
+Every @struct{thread} occupies the beginning of its own page of
+memory.  The rest of the page is used for the thread's stack, which
+grows downward from the end of the page.  It looks like this:
+
+@example
+        4 kB +---------------------------------+
+             |          kernel stack           |
+             |                |                |
+             |                |                |
+             |                V                |
+             |         grows downward          |
+             |                                 |
+             |                                 |
+             |                                 |
+             |                                 |
+             |                                 |
+             |                                 |
+             |                                 |
+             |                                 |
+             +---------------------------------+
+             |              magic              |
+             |                :                |
+             |                :                |
+             |               name              |
+             |              status             |
+        0 kB +---------------------------------+
+@end example
+
+The upshot of this is twofold.  First, @struct{thread} must not be
+allowed to grow too big.  If it does, then there will not be enough
+room for the kernel stack.  Our base @struct{thread} is only a few
+bytes in size.  It probably should stay well under 1 kB.
+
+Second, kernel stacks must not be allowed to grow too large.  If a
+stack overflows, it will corrupt the thread state.  Thus, kernel
+functions should not allocate large structures or arrays as non-static
+local variables.  Use dynamic allocation with @func{malloc} or
+@func{palloc_get_page} instead.
+
+This brings us to the purpose of @struct{thread}'s @code{magic}
+member.  If a thread's stack does overflow, then @code{magic} will be
+the first member of @struct{thread} to be overwritten, because it is
+closest to the kernel stack.  Thus, some of the thread functions
+(notably @func{thread_current}) check that @code{magic} has the proper
+value.
+
+@node Thread Functions
+@subsection Thread Functions
+
+@file{threads/thread.c} implements several public functions for
+thread support.  Let's take a look at some of them:
+
+@deftypefun void thread_init (void)
+Called by @func{main} to initialize the thread system.  Its main
+purpose is to create a @struct{thread} for Pintos's initial thread.
+This is possible because the Pintos loader sets up the initial
+thread's stack at the end of a page.  Before @func{thread_init} runs,
+@func{thread_current} will fail because the running thread's
+@code{magic} value is incorrect.  Lots of functions call
+@func{thread_current} directly or indirectly, including
+@func{lock_acquire} for locking a lock, so @func{thread_init} is
+called early in Pintos initialization.
+@end deftypefun
+
+@deftypefun void thread_start (void)
+Called by @func{main} to start the scheduler.  Creates the idle
+thread, that is, the thread that is scheduled when no other thread is
+ready.  Then enables interrupts, which enables the scheduler because
+processes are rescheduled in the return path from the timer
+interrupt.  FIXME
+@end deftypefun
+
+@deftypefun void thread_tick (void)
+Called by @func{timer_interrupt} on every timer interrupt.  Just
+increments counters that keep track of how often various kinds of
+threads run.
+@end deftypefun
+
+@deftypefun void thread_print_stats (void)
+Prints the statistics kept by @func{thread_ticK] to the console.
+Called when Pintos is terminating.
+@end deftypefun
+
+@deftypefun void thread_create (const char *@var{name}, int @var{priority}, @
+            thread_func *@var{func}, void *@var{aux}) Creates and
+starts a new thread named @var{name} with the given @var{priority},
+returning the new thread's tid.  The thread executes @var{func},
+passing @var{aux} as the function's single argument.
+
+@func{thread_create} works by allocating a page for the thread's
+@struct{thread} and stack and initializing its members, then setting
+up a set of fake stack frames for it (we'll talk more about this
+later).  The thread was initialized in the blocked state, so the final
+action before returning is to unblock it, allowing the new thread to
+be scheduled.
+@end deftypefun