RANDOM_REPLACEMENT, extra credit.  Update documentation, grading.
 project, so you don't need to make sure that the previous projects also
 compile.
 
-@node Conditional Compilation
-@section Conditional Compilation
-
-Given the scope and complexity of your assignments this quarter, you
-may find it convenient while coding and debugging (and we will find it
-convenient while grading) to be able to independently turn different
-parts of the assignments on and off.  To do this, choose a macro name
-and use it in conditional
-compilation directives, e.g.:
-
-@example
-#ifdef @var{NAME}
-@dots{}your code@dots{}
-#endif
-@end example
-
-In general, the code that you turn in must not depend on conditional
-compilation directives.  Project code should be written so that all of
-the subproblems for the project function together, and it should
-compile properly without the need for any new macros to be defined.
-There are a few exceptions:
-
-@itemize @bullet
-@item
-Problem 1-3, the advanced scheduler.  We must be able to turn this on
-and off with a compile-time directive.  You must use the macro name we
-specify for that part.  @xref{Problem 1-3 Advanced Scheduler}, for
-details.
-
-@item
-Problem 3-2, paging to and from disk.  Your page replacement policy must
-default to LRU-like replacement, but we must be able to choose a random
-replacement policy with a compile-time directive.  You must use the
-macro name we specify for that part.  @xref{Problem 3-2 Paging To and
-From Disk}, for details.
-
-@item
-Code written for extra credit may be included conditionally.  If the
-extra credit code changes the normally expected functionality of the
-code, then it @emph{must} be included conditionally, and it must not
-be enabled by default.
-@end itemize
-
-You can use @file{constants.h} in @file{pintos/src} to define macros
-for conditional compilation.  We will replace the @file{constants.h}
-that you supply with one of our own when we test your code, so do not
-define anything important in it.
+Project code should be written so that all of the subproblems for the
+project function together, that is, without the need to rebuild with
+different macros defined, etc.  If you do extra credit work that
+changes normal Pintos behavior so as to interfere with grading, then
+you must implement it so that it only acts that way when given a
+special command-line option of the form @option{-o @var{name}}, where
+@var{name} is a name of your choice.  You can add such an option by
+modifying @func{argv_init} in @file{threads/init.c}.
 
 @node C99
 @section C99
 
 at least one workload of your own design (i.e.@: in addition to the
 provided test).
 
-You must write your code so that we can turn the MLFQS on and off at
-compile time.  By default, it must be off, but we must be able to turn
-it on by inserting the line @code{#define MLFQS 1} in
-@file{constants.h}.  @xref{Conditional Compilation}, for details.
+You must write your code so that we can choose a scheduling algorithm
+policy at Pintos startup time.  By default, the round-robin scheduler
+must be active, but we must be able to choose the MLFQS by invoking
+@command{pintos} with the @option{-o mlfqs} option.  Passing this
+option sets @code{enable_mlfqs}, declared in @file{threads/init.h}, to
+true.
 
 @node Threads FAQ
 @section FAQ
 
 page replacement policy.  The canonical example of a poor page
 replacement policy is random replacement.
 
-You must write your code so that we can choose a page replacement policy
-at compile time.  By default, the LRU-like algorithm must be in effect,
-but we must be able to choose random replacement by inserting the line
-@code{#define RANDOM_REPLACEMENT 1} in @file{constants.h}.
-@xref{Conditional Compilation}, for details.
+You must write your code so that we can choose a page replacement
+policy at Pintos startup time.  By default, the LRU-like algorithm
+must be in effect, but we must be able to choose random replacement by
+invoking @command{pintos} with the @option{-o random-paging} option.
+Passing this option sets @code{enable_random_paging}, declared in
+@file{threads/init.h}, to true.
 
 Since you will already be paging from disk, you should implement a
 ``lazy'' loading scheme for new processes.  When a process is created,
 
 \f
 # Source tarballs.
 
-# Extracts the group's source files into pintos/src,
-# applies any patches providing in the grading directory,
-# and installs a default pintos/src/constants.h
+# Extracts the group's source files into pintos/src
+# and applies any patches providing in the grading directory.
 sub extract_sources {
     # Make sure the output dir exists.
     -d ("output") || mkdir ("output") or die "output: mkdir: $!\n";
        xsystem ("patch -fs -p0 < $patch",
                 LOG => $stem, DIE => "applying patch $stem failed\n");
     }
-
-    # Install default pintos/src/constants.h (which is empty).
-    open (CONSTANTS, ">pintos/src/constants.h")
-       or die "constants.h: create: $!\n";
-    close CONSTANTS;
 }
 
 # Returns the name of the tarball to extract.
 
 #include "threads/thread.h"
 #include "devices/timer.h"
 
-#ifdef MLFQS
-#error This test not applicable with MLFQS enabled.
-#endif
-
 static void test_sleep (int thread_cnt, int iterations);
 
 void
 test (void) 
 {
+  /* This test does not work with the MLFQS. */
+  ASSERT (!enable_mlfqs);
+
   test_sleep (5, 7);
 }
 \f
 
 #include "threads/thread.h"
 #include "devices/timer.h"
 
-#ifdef MLFQS
-#error This test not applicable with MLFQS enabled.
-#endif
-
 static void test_sleep (int thread_cnt, int iterations);
 
 void
 test (void) 
 {
+  /* This test does not work with the MLFQS. */
+  ASSERT (!enable_mlfqs);
+
   test_sleep (5, 1);
 }
 \f
 
    <gmh@leland.stanford.edu>, Yu Ping Hu <yph@cs.stanford.edu>.
    Modified by arens. */
 
-#ifdef MLFQS
-#error This test not applicable with MLFQS enabled.
-#endif
-
 #include "threads/test.h"
 #include <stdio.h>
 #include "threads/synch.h"
 void
 test (void) 
 {
+  /* This test does not work with the MLFQS. */
+  ASSERT (!enable_mlfqs);
+
   /* Make sure our priority is the default. */
   ASSERT (thread_get_priority () == PRI_DEFAULT);
 
 
    <gmh@leland.stanford.edu>, Yu Ping Hu <yph@cs.stanford.edu>.
    Modified by arens. */
 
-#ifdef MLFQS
-#error This test not applicable with MLFQS enabled.
-#endif
-
 #include "threads/test.h"
 #include <stdio.h>
 #include "threads/synch.h"
 void
 test (void) 
 {
+  /* This test does not work with the MLFQS. */
+  ASSERT (!enable_mlfqs);
+
   /* Make sure our priority is the default. */
   ASSERT (thread_get_priority () == PRI_DEFAULT);
 
 
    <gmh@leland.stanford.edu>, Yu Ping Hu <yph@cs.stanford.edu>.
    Modified by arens. */
 
-#ifdef MLFQS
-#error This test not applicable with MLFQS enabled.
-#endif
-
 #include "threads/test.h"
 #include <stdio.h>
 #include "threads/synch.h"
 void
 test (void) 
 {
+  /* This test does not work with the MLFQS. */
+  ASSERT (!enable_mlfqs);
+
   /* Make sure our priority is the default. */
   ASSERT (thread_get_priority () == PRI_DEFAULT);
 
 
    <gmh@leland.stanford.edu>, Yu Ping Hu <yph@cs.stanford.edu>.
    Modified by arens. */
 
-#ifdef MLFQS
-#error This test not applicable with MLFQS enabled.
-#endif
-
 #include "threads/test.h"
 #include <stdio.h>
 #include "devices/timer.h"
 void
 test (void) 
 {
+  /* This test does not work with the MLFQS. */
+  ASSERT (!enable_mlfqs);
+
   /* Make sure our priority is the default. */
   ASSERT (thread_get_priority () == PRI_DEFAULT);
 
 
    <gmh@leland.stanford.edu>, Yu Ping Hu <yph@cs.stanford.edu>.
    Modified by arens. */
 
-#ifdef MLFQS
-#error This test not applicable with MLFQS enabled.
-#endif
-
 #include "threads/test.h"
 #include <stdio.h>
 #include "threads/synch.h"
 void
 test (void) 
 {
+  /* This test does not work with the MLFQS. */
+  ASSERT (!enable_mlfqs);
+
   /* Make sure our priority is the default. */
   ASSERT (thread_get_priority () == PRI_DEFAULT);
 
 
 # Runs $test in directory output/$test.
 # Returns 'ok' if it went ok, otherwise an explanation.
 sub run_test {
-    # Change constants.h if necessary.
-    my ($defines) = $test ne 'mlfqs-on' ? "" : "#define MLFQS 1\n";
-    if ($defines ne snarf ("pintos/src/constants.h")) {
-       open (CONSTANTS, ">pintos/src/constants.h");
-       print CONSTANTS $defines;
-       close (CONSTANTS);
-    }
-
     # Changes devices/timer.c if necessary.
     my ($new_time_slice) = $test eq 'priority-fifo' ? 100 : 1;
     my (@timer_c) = snarf ("pintos/src/devices/timer.c");
 
     # Run.
     my ($timeout) = $test !~ /^mlfqs/ ? 15 : 600;
-    return run_pintos (["-v", "run", "-q"],
+    my (@command) = ("-v", "run", "-q");
+    push (@command, "-o mlfqs") if $test eq 'mlfqs-on';
+    return run_pintos (\@command,
                       CHDIR => "pintos/src/threads/build",
                       LOG => "$test/run",
                       TIMEOUT => $timeout);
 
 
 # Compiler and assembler options.
 DEFINES += -DKERNEL
-CPPFLAGS = -nostdinc -I../.. -I- -I../../lib -I../../lib/kernel        \
-          -include constants.h
+CPPFLAGS = -nostdinc -I../.. -I- -I../../lib -I../../lib/kernel
 
 # Core kernel.
 threads_SRC  = threads/init.c          # Main program.
 
+++ /dev/null
-/* Use this header file to define macros for configuring
-   compilation.  This file will be replaced by the TAs when your
-   code is tested, using the macros described in the course
-   documentation.  Your code should not require other macros to
-   be defined here to function properly. */
-
-/* Example definition. */
-/*#define MACRONAME 1 */
 
 #include "threads/thread.h"
 #include "devices/timer.h"
 
-#ifdef MLFQS
-#error This test not applicable with MLFQS enabled.
-#endif
-
 static void test_sleep (int thread_cnt, int iterations);
 
 void
 test (void) 
 {
+  /* This test does not work with the MLFQS. */
+  ASSERT (!enable_mlfqs);
+
   /* Easy test: 5 threads sleep once each. */
   test_sleep (5, 1);
 
 
    <gmh@leland.stanford.edu>, Yu Ping Hu <yph@cs.stanford.edu>.
    Modified by arens. */
 
-#ifdef MLFQS
-#error This test not applicable with MLFQS enabled.
-#endif
-
 #include "threads/test.h"
 #include <stdio.h>
 #include "threads/synch.h"
 void
 test (void) 
 {
+  /* This test does not work with the MLFQS. */
+  ASSERT (!enable_mlfqs);
+
   /* Make sure our priority is the default. */
   ASSERT (thread_get_priority () == PRI_DEFAULT);
 
 
 /* Page directory with kernel mappings only. */
 uint32_t *base_page_dir;
 
-#ifdef FILESYS
-/* -f: Format the filesystem? */
-static bool format_filesys;
-#endif
+/* -o mlfqs:
+   If false (default), use round-robin scheduler.
+   If true, use multi-level feedback queue scheduler. */
+bool enable_mlfqs;
 
 #ifdef USERPROG
 /* -ex: Initial program to run. */
 static char *initial_program;
 #endif
 
+#ifdef VM
+/* -o random-paging:
+   If false (default), use LRU page replacement policy.
+   If true, use random page replacement policy. */
+bool enable_random_paging;
+#endif
+
+#ifdef FILESYS
+/* -f: Format the filesystem? */
+static bool format_filesys;
+#endif
+
 /* -q: Power off after kernel tasks complete? */
 bool power_off_when_done;
 
 
   /* Parse the words. */
   for (i = 0; i < argc; i++)
-    if (!strcmp (argv[i], "-rs")) 
+    if (!strcmp (argv[i], "-o"))
+      {
+        i++;
+        if (!strcmp (argv[i], "mlfqs"))
+          enable_mlfqs = true;
+#ifdef VM
+        else if (!strcmp (argv[i], "random-paging"))
+          enable_random_paging = true;
+#endif
+        else
+          PANIC ("unknown option `-o %s' (use -u for help)", argv[i]);
+      }
+    else if (!strcmp (argv[i], "-rs")) 
       random_init (atoi (argv[++i]));
     else if (!strcmp (argv[i], "-q"))
       power_off_when_done = true;
       {
         printf (
           "Kernel options:\n"
-          " -rs SEED            Set random seed to SEED.\n"
+          " -o mlfqs            Use multi-level feedback queue scheduler.\n"
 #ifdef USERPROG
           " -ex 'PROG [ARG...]' Run PROG, passing the optional arguments.\n"
           " -ul USER_MAX        Limit user memory to USER_MAX pages.\n"
 #endif
+#ifdef VM
+          " -o random-paging    Use random page replacement policy.\n"
+#endif
 #ifdef FILESYS
           " -f                  Format the filesystem disk (hdb or hd0:1).\n"
           " -ci FILE SIZE       Copy SIZE bytes from the scratch disk (hdc\n"
           " -r FILE             Delete FILE.\n"
           " -ls                 List files in the root directory.\n"
 #endif
+          " -rs SEED            Set random seed to SEED.\n"
           " -q                  Power off after doing requested actions.\n"
           " -u                  Print this help message and power off.\n"
           );
 
 /* Page directory with kernel mappings only. */
 extern uint32_t *base_page_dir;
 
+/* -o mlfqs:
+   If false (default), use round-robin scheduler.
+   If true, use multi-level feedback queue scheduler. */
+extern bool enable_mlfqs;
+
+#ifdef VM
+/* -o random-paging:
+   If false (default), use LRU page replacement policy.
+   If true, use random page replacement policy. */
+extern bool enable_random_paging;
+#endif
+
 /* -q: Power off when kernel tasks complete? */
 extern bool power_off_when_done;
 
 
 #include "threads/thread.h"
 #include "devices/timer.h"
 
-#ifdef MLFQS
-#error This test not applicable with MLFQS enabled.
-#endif
-
 static void test_sleep (int thread_cnt, int iterations);
 
 void
 test (void) 
 {
+  /* This test does not work with the MLFQS. */
+  ASSERT (!enable_mlfqs);
+
   /* Easy test: 5 threads sleep once each. */
   test_sleep (5, 1);
 
 
 #ifndef THREADS_TEST_H
 #define THREADS_TEST_H
 
+#include "threads/init.h"
+
 void test (void);
 
 #endif /* threads/test.h */