754d8688810e89db26a0215443cfcb96f30e7dd3
[pintos-anon] / solutions / p3.patch
1 Index: src/Makefile.build
2 diff -u src/Makefile.build~ src/Makefile.build
3 --- src/Makefile.build~ 2005-06-18 20:20:47.000000000 -0700
4 +++ src/Makefile.build 2006-04-08 18:52:50.000000000 -0700
5 @@ -53,7 +53,9 @@ userprog_SRC += userprog/gdt.c                # GDT in
6  userprog_SRC += userprog/tss.c         # TSS management.
7  
8  # No virtual memory code yet.
9 -#vm_SRC = vm/filename.c                        # Some file.
10 +vm_SRC = vm/page.c
11 +vm_SRC += vm/frame.c
12 +vm_SRC += vm/swap.c
13  
14  # Filesystem code.
15  filesys_SRC  = filesys/filesys.c       # Filesystem core.
16 Index: src/devices/timer.c
17 diff -u src/devices/timer.c~ src/devices/timer.c
18 --- src/devices/timer.c~ 2005-07-06 13:45:36.000000000 -0700
19 +++ src/devices/timer.c 2006-04-08 18:52:50.000000000 -0700
20 @@ -23,6 +23,9 @@ static volatile int64_t ticks;
21     Initialized by timer_calibrate(). */
22  static unsigned loops_per_tick;
23  
24 +/* Threads waiting in timer_sleep(). */
25 +static struct list wait_list;
26 +
27  static intr_handler_func timer_interrupt;
28  static bool too_many_loops (unsigned loops);
29  static void busy_wait (int64_t loops);
30 @@ -43,6 +46,8 @@ timer_init (void) 
31    outb (0x40, count >> 8);
32  
33    intr_register_ext (0x20, timer_interrupt, "8254 Timer");
34 +
35 +  list_init (&wait_list);
36  }
37  
38  /* Calibrates loops_per_tick, used to implement brief delays. */
39 @@ -87,15 +92,36 @@ timer_elapsed (int64_t then) 
40    return timer_ticks () - then;
41  }
42  
43 +/* Compares two threads based on their wake-up times. */
44 +static bool
45 +compare_threads_by_wakeup_time (const struct list_elem *a_,
46 +                                const struct list_elem *b_,
47 +                                void *aux UNUSED) 
48 +{
49 +  const struct thread *a = list_entry (a_, struct thread, timer_elem);
50 +  const struct thread *b = list_entry (b_, struct thread, timer_elem);
51 +
52 +  return a->wakeup_time < b->wakeup_time;
53 +}
54 +
55  /* Suspends execution for approximately TICKS timer ticks. */
56  void
57  timer_sleep (int64_t ticks) 
58  {
59 -  int64_t start = timer_ticks ();
60 +  struct thread *t = thread_current ();
61 +
62 +  /* Schedule our wake-up time. */
63 +  t->wakeup_time = timer_ticks () + ticks;
64  
65 +  /* Atomically insert the current thread into the wait list. */
66    ASSERT (intr_get_level () == INTR_ON);
67 -  while (timer_elapsed (start) < ticks) 
68 -    thread_yield ();
69 +  intr_disable ();
70 +  list_insert_ordered (&wait_list, &t->timer_elem,
71 +                       compare_threads_by_wakeup_time, NULL);
72 +  intr_enable ();
73 +
74 +  /* Wait. */
75 +  sema_down (&t->timer_sema);
76  }
77  
78  /* Suspends execution for approximately MS milliseconds. */
79 @@ -132,6 +158,16 @@ timer_interrupt (struct intr_frame *args
80  {
81    ticks++;
82    thread_tick ();
83 +
84 +  while (!list_empty (&wait_list))
85 +    {
86 +      struct thread *t = list_entry (list_front (&wait_list),
87 +                                     struct thread, timer_elem);
88 +      if (ticks < t->wakeup_time) 
89 +        break;
90 +      sema_up (&t->timer_sema);
91 +      list_pop_front (&wait_list);
92 +    }
93  }
94  
95  /* Returns true if LOOPS iterations waits for more than one timer
96 Index: src/threads/init.c
97 diff -u src/threads/init.c~ src/threads/init.c
98 --- src/threads/init.c~ 2006-01-29 13:32:55.000000000 -0800
99 +++ src/threads/init.c 2006-04-08 18:52:50.000000000 -0700
100 @@ -33,6 +33,8 @@
101  #include "filesys/filesys.h"
102  #include "filesys/fsutil.h"
103  #endif
104 +#include "vm/frame.h"
105 +#include "vm/swap.h"
106  
107  /* Amount of physical memory, in 4 kB pages. */
108  size_t ram_pages;
109 @@ -124,6 +126,9 @@ main (void)
110    filesys_init (format_filesys);
111  #endif
112  
113 +  frame_init ();
114 +  swap_init ();
115 +
116    printf ("Boot complete.\n");
117    
118    /* Run actions specified on kernel command line. */
119 Index: src/threads/interrupt.c
120 diff -u src/threads/interrupt.c~ src/threads/interrupt.c
121 --- src/threads/interrupt.c~ 2006-01-29 13:32:55.000000000 -0800
122 +++ src/threads/interrupt.c 2006-04-08 18:52:50.000000000 -0700
123 @@ -354,6 +354,8 @@ intr_handler (struct intr_frame *frame) 
124        in_external_intr = true;
125        yield_on_return = false;
126      }
127 +  else 
128 +    thread_current ()->user_esp = frame->esp;
129  
130    /* Invoke the interrupt's handler.
131       If there is no handler, invoke the unexpected interrupt
132 Index: src/threads/thread.c
133 diff -u src/threads/thread.c~ src/threads/thread.c
134 --- src/threads/thread.c~ 2006-04-08 12:09:39.000000000 -0700
135 +++ src/threads/thread.c 2006-04-08 18:52:50.000000000 -0700
136 @@ -13,6 +13,7 @@
137  #include "threads/synch.h"
138  #ifdef USERPROG
139  #include "userprog/process.h"
140 +#include "userprog/syscall.h"
141  #endif
142  
143  /* Random value for struct thread's `magic' member.
144 @@ -55,7 +56,8 @@ static void kernel_thread (thread_func *
145  static void idle (void *aux UNUSED);
146  static struct thread *running_thread (void);
147  static struct thread *next_thread_to_run (void);
148 -static void init_thread (struct thread *, const char *name, int priority);
149 +static void init_thread (struct thread *, const char *name, int priority,
150 +                         tid_t);
151  static bool is_thread (struct thread *) UNUSED;
152  static void *alloc_frame (struct thread *, size_t size);
153  static void schedule (void);
154 @@ -82,9 +84,8 @@ thread_init (void) 
155  
156    /* Set up a thread structure for the running thread. */
157    initial_thread = running_thread ();
158 -  init_thread (initial_thread, "main", PRI_DEFAULT);
159 +  init_thread (initial_thread, "main", PRI_DEFAULT, 0);
160    initial_thread->status = THREAD_RUNNING;
161 -  initial_thread->tid = allocate_tid ();
162  }
163  
164  /* Starts preemptive thread scheduling by enabling interrupts.
165 @@ -159,8 +160,8 @@ thread_create (const char *name, int pri
166      return TID_ERROR;
167  
168    /* Initialize thread. */
169 -  init_thread (t, name, priority);
170 -  tid = t->tid = allocate_tid ();
171 +  init_thread (t, name, priority, allocate_tid ());
172 +  tid = t->tid;
173  
174    /* Stack frame for kernel_thread(). */
175    kf = alloc_frame (t, sizeof *kf);
176 @@ -253,16 +254,19 @@ thread_tid (void) 
177  void
178  thread_exit (void) 
179  {
180 +  struct thread *t = thread_current ();
181 +
182    ASSERT (!intr_context ());
183  
184 +  syscall_exit ();
185  #ifdef USERPROG
186    process_exit ();
187  #endif
188 -
189 +  
190    /* Just set our status to dying and schedule another process.
191       We will be destroyed during the call to schedule_tail(). */
192    intr_disable ();
193 -  thread_current ()->status = THREAD_DYING;
194 +  t->status = THREAD_DYING;
195    schedule ();
196    NOT_REACHED ();
197  }
198 @@ -406,17 +410,28 @@ is_thread (struct thread *t)
199  /* Does basic initialization of T as a blocked thread named
200     NAME. */
201  static void
202 -init_thread (struct thread *t, const char *name, int priority)
203 +init_thread (struct thread *t, const char *name, int priority, tid_t tid)
204  {
205    ASSERT (t != NULL);
206    ASSERT (PRI_MIN <= priority && priority <= PRI_MAX);
207    ASSERT (name != NULL);
208  
209    memset (t, 0, sizeof *t);
210 +  t->tid = tid;
211    t->status = THREAD_BLOCKED;
212    strlcpy (t->name, name, sizeof t->name);
213    t->stack = (uint8_t *) t + PGSIZE;
214    t->priority = priority;
215 +  t->exit_code = -1;
216 +  t->wait_status = NULL;
217 +  list_init (&t->children);
218 +  sema_init (&t->timer_sema, 0);
219 +  t->pagedir = NULL;
220 +  t->pages = NULL;
221 +  t->bin_file = NULL;
222 +  list_init (&t->fds);
223 +  list_init (&t->mappings);
224 +  t->next_handle = 2;
225    t->magic = THREAD_MAGIC;
226  }
227  
228 Index: src/threads/thread.h
229 diff -u src/threads/thread.h~ src/threads/thread.h
230 --- src/threads/thread.h~ 2005-06-18 20:21:21.000000000 -0700
231 +++ src/threads/thread.h 2006-04-08 18:52:50.000000000 -0700
232 @@ -2,8 +2,10 @@
233  #define THREADS_THREAD_H
234  
235  #include <debug.h>
236 +#include <hash.h>
237  #include <list.h>
238  #include <stdint.h>
239 +#include "threads/synch.h"
240  
241  /* States in a thread's life cycle. */
242  enum thread_status
243 @@ -89,18 +91,49 @@ struct thread
244      uint8_t *stack;                     /* Saved stack pointer. */
245      int priority;                       /* Priority. */
246  
247 +    /* Owned by process.c. */
248 +    int exit_code;                      /* Exit code. */
249 +    struct wait_status *wait_status;    /* This process's completion status. */
250 +    struct list children;               /* Completion status of children. */
251 +
252      /* Shared between thread.c and synch.c. */
253      struct list_elem elem;              /* List element. */
254  
255 -#ifdef USERPROG
256 +    /* Alarm clock. */
257 +    int64_t wakeup_time;                /* Time to wake this thread up. */
258 +    struct list_elem timer_elem;        /* Element in timer_wait_list. */
259 +    struct semaphore timer_sema;        /* Semaphore. */
260 +
261      /* Owned by userprog/process.c. */
262      uint32_t *pagedir;                  /* Page directory. */
263 -#endif
264 +    struct hash *pages;                 /* Page table. */
265 +    struct file *bin_file;              /* The binary executable. */
266 +
267 +    /* Owned by syscall.c. */
268 +    struct list fds;                    /* List of file descriptors. */
269 +    struct list mappings;               /* Memory-mapped files. */
270 +    int next_handle;                    /* Next handle value. */
271 +    void *user_esp;                     /* User's stack pointer. */
272  
273      /* Owned by thread.c. */
274      unsigned magic;                     /* Detects stack overflow. */
275    };
276  
277 +/* Tracks the completion of a process.
278 +   Reference held by both the parent, in its `children' list,
279 +   and by the child, in its `wait_status' pointer. */
280 +struct wait_status
281 +  {
282 +    struct list_elem elem;              /* `children' list element. */
283 +    struct lock lock;                   /* Protects ref_cnt. */
284 +    int ref_cnt;                        /* 2=child and parent both alive,
285 +                                           1=either child or parent alive,
286 +                                           0=child and parent both dead. */
287 +    tid_t tid;                          /* Child thread id. */
288 +    int exit_code;                      /* Child exit code, if dead. */
289 +    struct semaphore dead;              /* 1=child alive, 0=child dead. */
290 +  };
291 +
292  void thread_init (void);
293  void thread_start (void);
294  
295 Index: src/userprog/exception.c
296 diff -u src/userprog/exception.c~ src/userprog/exception.c
297 --- src/userprog/exception.c~ 2006-01-29 13:32:56.000000000 -0800
298 +++ src/userprog/exception.c 2006-04-08 18:52:50.000000000 -0700
299 @@ -4,6 +4,7 @@
300  #include "userprog/gdt.h"
301  #include "threads/interrupt.h"
302  #include "threads/thread.h"
303 +#include "vm/page.h"
304  
305  /* Number of page faults processed. */
306  static long long page_fault_cnt;
307 @@ -148,9 +149,14 @@ page_fault (struct intr_frame *f) 
308    write = (f->error_code & PF_W) != 0;
309    user = (f->error_code & PF_U) != 0;
310  
311 -  /* To implement virtual memory, delete the rest of the function
312 -     body, and replace it with code that brings in the page to
313 -     which fault_addr refers. */
314 +  /* Allow the pager to try to handle it. */
315 +  if (user && not_present)
316 +    {
317 +      if (!page_in (fault_addr))
318 +        thread_exit ();
319 +      return;
320 +    }
321 +
322    printf ("Page fault at %p: %s error %s page in %s context.\n",
323            fault_addr,
324            not_present ? "not present" : "rights violation",
325 Index: src/userprog/pagedir.c
326 diff -u src/userprog/pagedir.c~ src/userprog/pagedir.c
327 --- src/userprog/pagedir.c~ 2006-01-29 13:32:56.000000000 -0800
328 +++ src/userprog/pagedir.c 2006-04-08 18:52:50.000000000 -0700
329 @@ -35,15 +35,7 @@ pagedir_destroy (uint32_t *pd) 
330    ASSERT (pd != base_page_dir);
331    for (pde = pd; pde < pd + pd_no (PHYS_BASE); pde++)
332      if (*pde & PG_P) 
333 -      {
334 -        uint32_t *pt = pde_get_pt (*pde);
335 -        uint32_t *pte;
336 -        
337 -        for (pte = pt; pte < pt + PGSIZE / sizeof *pte; pte++)
338 -          if (*pte & PG_P) 
339 -            palloc_free_page (pte_get_page (*pte));
340 -        palloc_free_page (pt);
341 -      }
342 +      palloc_free_page (pde_get_pt (*pde));
343    palloc_free_page (pd);
344  }
345  
346 Index: src/userprog/process.c
347 diff -u src/userprog/process.c~ src/userprog/process.c
348 --- src/userprog/process.c~ 2006-04-08 19:37:00.000000000 -0700
349 +++ src/userprog/process.c 2006-04-08 19:35:29.000000000 -0700
350 @@ -15,11 +15,25 @@
351  #include "threads/init.h"
352  #include "threads/interrupt.h"
353  #include "threads/mmu.h"
354 +#include "threads/malloc.h"
355  #include "threads/palloc.h"
356  #include "threads/thread.h"
357 +#include "vm/page.h"
358 +#include "vm/frame.h"
359  
360  static thread_func execute_thread NO_RETURN;
361 -static bool load (const char *cmdline, void (**eip) (void), void **esp);
362 +static bool load (const char *cmd_line, void (**eip) (void), void **esp);
363 +
364 +/* Data structure shared between process_execute() in the
365 +   invoking thread and execute_thread() in the newly invoked
366 +   thread. */
367 +struct exec_info 
368 +  {
369 +    const char *filename;               /* Program to load. */
370 +    struct semaphore load_done;         /* "Up"ed when loading complete. */
371 +    struct wait_status *wait_status;    /* Child process. */
372 +    bool success;                       /* Program successfully loaded? */
373 +  };
374  
375  /* Starts a new thread running a user program loaded from
376     FILENAME.  The new thread may be scheduled (and may even exit)
377 @@ -28,29 +42,37 @@ static bool load (const char *cmdline, v
378  tid_t
379  process_execute (const char *filename) 
380  {
381 -  char *fn_copy;
382 +  struct exec_info exec;
383 +  char thread_name[16];
384 +  char *save_ptr;
385    tid_t tid;
386  
387 -  /* Make a copy of FILENAME.
388 -     Otherwise there's a race between the caller and load(). */
389 -  fn_copy = palloc_get_page (0);
390 -  if (fn_copy == NULL)
391 -    return TID_ERROR;
392 -  strlcpy (fn_copy, filename, PGSIZE);
393 +  /* Initialize exec_info. */
394 +  exec.filename = filename;
395 +  sema_init (&exec.load_done, 0);
396  
397    /* Create a new thread to execute FILENAME. */
398 -  tid = thread_create (filename, PRI_DEFAULT, execute_thread, fn_copy);
399 -  if (tid == TID_ERROR)
400 -    palloc_free_page (fn_copy); 
401 +  strlcpy (thread_name, filename, sizeof thread_name);
402 +  strtok_r (thread_name, " ", &save_ptr);
403 +  tid = thread_create (thread_name, PRI_DEFAULT, execute_thread, &exec);
404 +  if (tid != TID_ERROR)
405 +    {
406 +      sema_down (&exec.load_done);
407 +      if (exec.success)
408 +        list_push_back (&thread_current ()->children, &exec.wait_status->elem);
409 +      else 
410 +        tid = TID_ERROR;
411 +    }
412 +
413    return tid;
414  }
415  
416  /* A thread function that loads a user process and starts it
417     running. */
418  static void
419 -execute_thread (void *filename_)
420 +execute_thread (void *exec_)
421  {
422 -  char *filename = filename_;
423 +  struct exec_info *exec = exec_;
424    struct intr_frame if_;
425    bool success;
426  
427 @@ -59,10 +81,28 @@ execute_thread (void *filename_)
428    if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
429    if_.cs = SEL_UCSEG;
430    if_.eflags = FLAG_IF | FLAG_MBS;
431 -  success = load (filename, &if_.eip, &if_.esp);
432 +  success = load (exec->filename, &if_.eip, &if_.esp);
433 +
434 +  /* Allocate wait_status. */
435 +  if (success)
436 +    {
437 +      exec->wait_status = thread_current ()->wait_status
438 +        = malloc (sizeof *exec->wait_status);
439 +      success = exec->wait_status != NULL; 
440 +    }
441  
442 -  /* If load failed, quit. */
443 -  palloc_free_page (filename);
444 +  /* Initialize wait_status. */
445 +  if (success) 
446 +    {
447 +      lock_init (&exec->wait_status->lock);
448 +      exec->wait_status->ref_cnt = 2;
449 +      exec->wait_status->tid = thread_current ()->tid;
450 +      sema_init (&exec->wait_status->dead, 0);
451 +    }
452 +  
453 +  /* Notify parent thread and clean up. */
454 +  exec->success = success;
455 +  sema_up (&exec->load_done);
456    if (!success) 
457      thread_exit ();
458  
459 @@ -76,18 +116,47 @@ execute_thread (void *filename_)
460    NOT_REACHED ();
461  }
462  
463 +/* Releases one reference to CS and, if it is now unreferenced,
464 +   frees it. */
465 +static void
466 +release_child (struct wait_status *cs) 
467 +{
468 +  int new_ref_cnt;
469 +  
470 +  lock_acquire (&cs->lock);
471 +  new_ref_cnt = --cs->ref_cnt;
472 +  lock_release (&cs->lock);
473 +
474 +  if (new_ref_cnt == 0)
475 +    free (cs);
476 +}
477 +
478  /* Waits for thread TID to die and returns its exit status.  If
479     it was terminated by the kernel (i.e. killed due to an
480     exception), returns -1.  If TID is invalid or if it was not a
481     child of the calling process, or if process_wait() has already
482     been successfully called for the given TID, returns -1
483 -   immediately, without waiting.
484 -
485 -   This function will be implemented in problem 2-2.  For now, it
486 -   does nothing. */
487 +   immediately, without waiting. */
488  int
489 -process_wait (tid_t child_tid UNUSED) 
490 +process_wait (tid_t child_tid) 
491  {
492 +  struct thread *cur = thread_current ();
493 +  struct list_elem *e;
494 +
495 +  for (e = list_begin (&cur->children); e != list_end (&cur->children);
496 +       e = list_next (e)) 
497 +    {
498 +      struct wait_status *cs = list_entry (e, struct wait_status, elem);
499 +      if (cs->tid == child_tid) 
500 +        {
501 +          int exit_code;
502 +          list_remove (e);
503 +          sema_down (&cs->dead);
504 +          exit_code = cs->exit_code;
505 +          release_child (cs);
506 +          return exit_code;
507 +        }
508 +    }
509    return -1;
510  }
511  
512 @@ -96,8 +165,35 @@ void
513  process_exit (void)
514  {
515    struct thread *cur = thread_current ();
516 +  struct list_elem *e, *next;
517    uint32_t *pd;
518  
519 +  printf ("%s: exit(%d)\n", cur->name, cur->exit_code);
520 +
521 +  /* Notify parent that we're dead. */
522 +  if (cur->wait_status != NULL) 
523 +    {
524 +      struct wait_status *cs = cur->wait_status;
525 +      cs->exit_code = cur->exit_code;
526 +      sema_up (&cs->dead);
527 +      release_child (cs);
528 +    }
529 +
530 +  /* Free entries of children list. */
531 +  for (e = list_begin (&cur->children); e != list_end (&cur->children);
532 +       e = next) 
533 +    {
534 +      struct wait_status *cs = list_entry (e, struct wait_status, elem);
535 +      next = list_remove (e);
536 +      release_child (cs);
537 +    }
538 +
539 +  /* Destroy the page hash table. */
540 +  page_exit ();
541 +  
542 +  /* Close executable (and allow writes). */
543 +  file_close (cur->bin_file);
544 +
545    /* Destroy the current process's page directory and switch back
546       to the kernel-only page directory. */
547    pd = cur->pagedir;
548 @@ -194,7 +290,7 @@ struct Elf32_Phdr
549  #define PF_W 2          /* Writable. */
550  #define PF_R 4          /* Readable. */
551  
552 -static bool setup_stack (void **esp);
553 +static bool setup_stack (const char *cmd_line, void **esp);
554  static bool validate_segment (const struct Elf32_Phdr *, struct file *);
555  static bool load_segment (struct file *file, off_t ofs, uint8_t *upage,
556                            uint32_t read_bytes, uint32_t zero_bytes,
557 @@ -205,13 +301,15 @@ static bool load_segment (struct file *f
558     and its initial stack pointer into *ESP.
559     Returns true if successful, false otherwise. */
560  bool
561 -load (const char *filename, void (**eip) (void), void **esp) 
562 +load (const char *cmd_line, void (**eip) (void), void **esp) 
563  {
564    struct thread *t = thread_current ();
565 +  char filename[NAME_MAX + 2];
566    struct Elf32_Ehdr ehdr;
567    struct file *file = NULL;
568    off_t file_ofs;
569    bool success = false;
570 +  char *cp;
571    int i;
572  
573    /* Allocate and activate page directory. */
574 @@ -220,13 +318,28 @@ load (const char *filename, void (**eip)
575      goto done;
576    process_activate ();
577  
578 +  /* Create page hash table. */
579 +  t->pages = malloc (sizeof *t->pages);
580 +  if (t->pages == NULL)
581 +    goto done;
582 +  hash_init (t->pages, page_hash, page_less, NULL);
583 +
584 +  /* Extract filename from command line. */
585 +  while (*cmd_line == ' ')
586 +    cmd_line++;
587 +  strlcpy (filename, cmd_line, sizeof filename);
588 +  cp = strchr (filename, ' ');
589 +  if (cp != NULL)
590 +    *cp = '\0';
591 +
592    /* Open executable file. */
593 -  file = filesys_open (filename);
594 +  t->bin_file = file = filesys_open (filename);
595    if (file == NULL) 
596      {
597        printf ("load: %s: open failed\n", filename);
598        goto done; 
599      }
600 +  file_deny_write (t->bin_file);
601  
602    /* Read and verify executable header. */
603    if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr
604 @@ -301,7 +414,7 @@ load (const char *filename, void (**eip)
605      }
606  
607    /* Set up stack. */
608 -  if (!setup_stack (esp))
609 +  if (!setup_stack (cmd_line, esp))
610      goto done;
611  
612    /* Start address. */
613 @@ -311,14 +424,11 @@ load (const char *filename, void (**eip)
614  
615   done:
616    /* We arrive here whether the load is successful or not. */
617 -  file_close (file);
618    return success;
619  }
620  \f
621  /* load() helpers. */
622  
623 -static bool install_page (void *upage, void *kpage, bool writable);
624 -
625  /* Checks whether PHDR describes a valid, loadable segment in
626     FILE and returns true if so, false otherwise. */
627  static bool
628 @@ -387,79 +497,127 @@ load_segment (struct file *file, off_t o
629    ASSERT (pg_ofs (upage) == 0);
630    ASSERT (ofs % PGSIZE == 0);
631  
632 -  file_seek (file, ofs);
633    while (read_bytes > 0 || zero_bytes > 0) 
634      {
635 -      /* Calculate how to fill this page.
636 -         We will read PAGE_READ_BYTES bytes from FILE
637 -         and zero the final PAGE_ZERO_BYTES bytes. */
638        size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
639        size_t page_zero_bytes = PGSIZE - page_read_bytes;
640 -
641 -      /* Get a page of memory. */
642 -      uint8_t *kpage = palloc_get_page (PAL_USER);
643 -      if (kpage == NULL)
644 +      struct page *p = page_allocate (upage, !writable);
645 +      if (p == NULL)
646          return false;
647 -
648 -      /* Load this page. */
649 -      if (file_read (file, kpage, page_read_bytes) != (int) page_read_bytes)
650 -        {
651 -          palloc_free_page (kpage);
652 -          return false; 
653 -        }
654 -      memset (kpage + page_read_bytes, 0, page_zero_bytes);
655 -
656 -      /* Add the page to the process's address space. */
657 -      if (!install_page (upage, kpage, writable)) 
658 +      if (page_read_bytes > 0) 
659          {
660 -          palloc_free_page (kpage);
661 -          return false; 
662 +          p->file = file;
663 +          p->file_offset = ofs;
664 +          p->file_bytes = page_read_bytes;
665          }
666 -
667 -      /* Advance. */
668        read_bytes -= page_read_bytes;
669        zero_bytes -= page_zero_bytes;
670 +      ofs += page_read_bytes;
671        upage += PGSIZE;
672      }
673    return true;
674  }
675  
676 -/* Create a minimal stack by mapping a zeroed page at the top of
677 -   user virtual memory. */
678 +/* Reverse the order of the ARGC pointers to char in ARGV. */
679 +static void
680 +reverse (int argc, char **argv) 
681 +{
682 +  for (; argc > 1; argc -= 2, argv++) 
683 +    {
684 +      char *tmp = argv[0];
685 +      argv[0] = argv[argc - 1];
686 +      argv[argc - 1] = tmp;
687 +    }
688 +}
689
690 +/* Pushes the SIZE bytes in BUF onto the stack in KPAGE, whose
691 +   page-relative stack pointer is *OFS, and then adjusts *OFS
692 +   appropriately.  The bytes pushed are rounded to a 32-bit
693 +   boundary.
694 +
695 +   If successful, returns a pointer to the newly pushed object.
696 +   On failure, returns a null pointer. */
697 +static void *
698 +push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size) 
699 +{
700 +  size_t padsize = ROUND_UP (size, sizeof (uint32_t));
701 +  if (*ofs < padsize)
702 +    return NULL;
703 +
704 +  *ofs -= padsize;
705 +  memcpy (kpage + *ofs + (padsize - size), buf, size);
706 +  return kpage + *ofs + (padsize - size);
707 +}
708 +
709 +/* Sets up command line arguments in KPAGE, which will be mapped
710 +   to UPAGE in user space.  The command line arguments are taken
711 +   from CMD_LINE, separated by spaces.  Sets *ESP to the initial
712 +   stack pointer for the process. */
713  static bool
714 -setup_stack (void **esp) 
715 +init_cmd_line (uint8_t *kpage, uint8_t *upage, const char *cmd_line,
716 +               void **esp) 
717  {
718 -  uint8_t *kpage;
719 -  bool success = false;
720 +  size_t ofs = PGSIZE;
721 +  char *const null = NULL;
722 +  char *cmd_line_copy;
723 +  char *karg, *saveptr;
724 +  int argc;
725 +  char **argv;
726 +
727 +  /* Push command line string. */
728 +  cmd_line_copy = push (kpage, &ofs, cmd_line, strlen (cmd_line) + 1);
729 +  if (cmd_line_copy == NULL)
730 +    return false;
731 +
732 +  if (push (kpage, &ofs, &null, sizeof null) == NULL)
733 +    return false;
734  
735 -  kpage = palloc_get_page (PAL_USER | PAL_ZERO);
736 -  if (kpage != NULL) 
737 +  /* Parse command line into arguments
738 +     and push them in reverse order. */
739 +  argc = 0;
740 +  for (karg = strtok_r (cmd_line_copy, " ", &saveptr); karg != NULL;
741 +       karg = strtok_r (NULL, " ", &saveptr))
742      {
743 -      success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true);
744 -      if (success)
745 -        *esp = PHYS_BASE;
746 -      else
747 -        palloc_free_page (kpage);
748 +      void *uarg = upage + (karg - (char *) kpage);
749 +      if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
750 +        return false;
751 +      argc++;
752      }
753 -  return success;
754 +
755 +  /* Reverse the order of the command line arguments. */
756 +  argv = (char **) (upage + ofs);
757 +  reverse (argc, (char **) (kpage + ofs));
758 +
759 +  /* Push argv, argc, "return address". */
760 +  if (push (kpage, &ofs, &argv, sizeof argv) == NULL
761 +      || push (kpage, &ofs, &argc, sizeof argc) == NULL
762 +      || push (kpage, &ofs, &null, sizeof null) == NULL)
763 +    return false;
764 +
765 +  /* Set initial stack pointer. */
766 +  *esp = upage + ofs;
767 +  return true;
768  }
769  
770 -/* Adds a mapping from user virtual address UPAGE to kernel
771 -   virtual address KPAGE to the page table.
772 -   If WRITABLE is true, the user process may modify the page;
773 -   otherwise, it is read-only.
774 -   UPAGE must not already be mapped.
775 -   KPAGE should probably be a page obtained from the user pool
776 -   with palloc_get_page().
777 -   Returns true on success, false if UPAGE is already mapped or
778 -   if memory allocation fails. */
779 +/* Create a minimal stack for T by mapping a page at the
780 +   top of user virtual memory.  Fills in the page using CMD_LINE
781 +   and sets *ESP to the stack pointer. */
782  static bool
783 -install_page (void *upage, void *kpage, bool writable)
784 +setup_stack (const char *cmd_line, void **esp) 
785  {
786 -  struct thread *t = thread_current ();
787 -
788 -  /* Verify that there's not already a page at that virtual
789 -     address, then map our page there. */
790 -  return (pagedir_get_page (t->pagedir, upage) == NULL
791 -          && pagedir_set_page (t->pagedir, upage, kpage, writable));
792 +  struct page *page = page_allocate (((uint8_t *) PHYS_BASE) - PGSIZE, false);
793 +  if (page != NULL) 
794 +    {
795 +      page->frame = frame_alloc_and_lock (page);
796 +      if (page->frame != NULL)
797 +        {
798 +          bool ok;
799 +          page->read_only = false;
800 +          page->private = false;
801 +          ok = init_cmd_line (page->frame->base, page->addr, cmd_line, esp);
802 +          frame_unlock (page->frame);
803 +          return ok;
804 +        }
805 +    }
806 +  return false;
807  }
808 Index: src/userprog/syscall.c
809 diff -u src/userprog/syscall.c~ src/userprog/syscall.c
810 --- src/userprog/syscall.c~ 2005-06-18 20:21:21.000000000 -0700
811 +++ src/userprog/syscall.c 2006-04-08 19:36:04.000000000 -0700
812 @@ -1,20 +1,557 @@
813  #include "userprog/syscall.h"
814  #include <stdio.h>
815 +#include <string.h>
816  #include <syscall-nr.h>
817 +#include "userprog/process.h"
818 +#include "userprog/pagedir.h"
819 +#include "devices/kbd.h"
820 +#include "filesys/directory.h"
821 +#include "filesys/filesys.h"
822 +#include "filesys/file.h"
823 +#include "threads/init.h"
824  #include "threads/interrupt.h"
825 +#include "threads/malloc.h"
826 +#include "threads/mmu.h"
827 +#include "threads/palloc.h"
828  #include "threads/thread.h"
829 -
830 +#include "vm/page.h"
831
832
833 +static int sys_halt (void);
834 +static int sys_exit (int status);
835 +static int sys_exec (const char *ufile);
836 +static int sys_wait (tid_t);
837 +static int sys_create (const char *ufile, unsigned initial_size);
838 +static int sys_remove (const char *ufile);
839 +static int sys_open (const char *ufile);
840 +static int sys_filesize (int handle);
841 +static int sys_read (int handle, void *udst_, unsigned size);
842 +static int sys_write (int handle, void *usrc_, unsigned size);
843 +static int sys_seek (int handle, unsigned position);
844 +static int sys_tell (int handle);
845 +static int sys_close (int handle);
846 +static int sys_mmap (int handle, void *addr);
847 +static int sys_munmap (int mapping);
848
849  static void syscall_handler (struct intr_frame *);
850 -
851 +static void copy_in (void *, const void *, size_t);
852
853  void
854  syscall_init (void) 
855  {
856    intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall");
857  }
858
859 +/* System call handler. */
860 +static void
861 +syscall_handler (struct intr_frame *f) 
862 +{
863 +  typedef int syscall_function (int, int, int);
864 +
865 +  /* A system call. */
866 +  struct syscall 
867 +    {
868 +      size_t arg_cnt;           /* Number of arguments. */
869 +      syscall_function *func;   /* Implementation. */
870 +    };
871 +
872 +  /* Table of system calls. */
873 +  static const struct syscall syscall_table[] =
874 +    {
875 +      {0, (syscall_function *) sys_halt},
876 +      {1, (syscall_function *) sys_exit},
877 +      {1, (syscall_function *) sys_exec},
878 +      {1, (syscall_function *) sys_wait},
879 +      {2, (syscall_function *) sys_create},
880 +      {1, (syscall_function *) sys_remove},
881 +      {1, (syscall_function *) sys_open},
882 +      {1, (syscall_function *) sys_filesize},
883 +      {3, (syscall_function *) sys_read},
884 +      {3, (syscall_function *) sys_write},
885 +      {2, (syscall_function *) sys_seek},
886 +      {1, (syscall_function *) sys_tell},
887 +      {1, (syscall_function *) sys_close},
888 +      {2, (syscall_function *) sys_mmap},
889 +      {1, (syscall_function *) sys_munmap},
890 +    };
891  
892 +  const struct syscall *sc;
893 +  unsigned call_nr;
894 +  int args[3];
895 +
896 +  /* Get the system call. */
897 +  copy_in (&call_nr, f->esp, sizeof call_nr);
898 +  if (call_nr >= sizeof syscall_table / sizeof *syscall_table)
899 +    thread_exit ();
900 +  sc = syscall_table + call_nr;
901 +
902 +  /* Get the system call arguments. */
903 +  ASSERT (sc->arg_cnt <= sizeof args / sizeof *args);
904 +  memset (args, 0, sizeof args);
905 +  copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * sc->arg_cnt);
906 +
907 +  /* Execute the system call,
908 +     and set the return value. */
909 +  f->eax = sc->func (args[0], args[1], args[2]);
910 +}
911
912 +/* Copies SIZE bytes from user address USRC to kernel address
913 +   DST.
914 +   Call thread_exit() if any of the user accesses are invalid. */
915  static void
916 -syscall_handler (struct intr_frame *f UNUSED) 
917 +copy_in (void *dst_, const void *usrc_, size_t size) 
918 +{
919 +  uint8_t *dst = dst_;
920 +  const uint8_t *usrc = usrc_;
921 +
922 +  while (size > 0) 
923 +    {
924 +      size_t chunk_size = PGSIZE - pg_ofs (usrc);
925 +      if (chunk_size > size)
926 +        chunk_size = size;
927 +      
928 +      if (!page_lock (usrc, false))
929 +        thread_exit ();
930 +      memcpy (dst, usrc, chunk_size);
931 +      page_unlock (usrc);
932 +
933 +      dst += chunk_size;
934 +      usrc += chunk_size;
935 +      size -= chunk_size;
936 +    }
937 +}
938
939 +/* Creates a copy of user string US in kernel memory
940 +   and returns it as a page that must be freed with
941 +   palloc_free_page().
942 +   Truncates the string at PGSIZE bytes in size.
943 +   Call thread_exit() if any of the user accesses are invalid. */
944 +static char *
945 +copy_in_string (const char *us) 
946 +{
947 +  char *ks;
948 +  char *upage;
949 +  size_t length;
950
951 +  ks = palloc_get_page (0);
952 +  if (ks == NULL) 
953 +    thread_exit ();
954 +
955 +  length = 0;
956 +  for (;;) 
957 +    {
958 +      upage = pg_round_down (us);
959 +      if (!page_lock (upage, false))
960 +        goto lock_error;
961 +
962 +      for (; us < upage + PGSIZE; us++) 
963 +        {
964 +          ks[length++] = *us;
965 +          if (*us == '\0') 
966 +            {
967 +              page_unlock (upage);
968 +              return ks; 
969 +            }
970 +          else if (length >= PGSIZE) 
971 +            goto too_long_error;
972 +        }
973 +
974 +      page_unlock (upage);
975 +    }
976 +
977 + too_long_error:
978 +  page_unlock (upage);
979 + lock_error:
980 +  palloc_free_page (ks);
981 +  thread_exit ();
982 +}
983
984 +/* Halt system call. */
985 +static int
986 +sys_halt (void)
987 +{
988 +  power_off ();
989 +}
990
991 +/* Exit system call. */
992 +static int
993 +sys_exit (int exit_code) 
994 +{
995 +  thread_current ()->exit_code = exit_code;
996 +  thread_exit ();
997 +  NOT_REACHED ();
998 +}
999
1000 +/* Exec system call. */
1001 +static int
1002 +sys_exec (const char *ufile) 
1003 +{
1004 +  tid_t tid;
1005 +  char *kfile = copy_in_string (ufile);
1006
1007 +  tid = process_execute (kfile);
1008
1009 +  palloc_free_page (kfile);
1010
1011 +  return tid;
1012 +}
1013
1014 +/* Wait system call. */
1015 +static int
1016 +sys_wait (tid_t child) 
1017 +{
1018 +  return process_wait (child);
1019 +}
1020
1021 +/* Create system call. */
1022 +static int
1023 +sys_create (const char *ufile, unsigned initial_size) 
1024 +{
1025 +  char *kfile = copy_in_string (ufile);
1026 +  bool ok = filesys_create (kfile, initial_size);
1027 +  palloc_free_page (kfile);
1028
1029 +  return ok;
1030 +}
1031
1032 +/* Remove system call. */
1033 +static int
1034 +sys_remove (const char *ufile) 
1035 +{
1036 +  char *kfile = copy_in_string (ufile);
1037 +  bool ok = filesys_remove (kfile);
1038 +  palloc_free_page (kfile);
1039
1040 +  return ok;
1041 +}
1042 +\f
1043 +/* A file descriptor, for binding a file handle to a file. */
1044 +struct file_descriptor
1045 +  {
1046 +    struct list_elem elem;      /* List element. */
1047 +    struct file *file;          /* File. */
1048 +    int handle;                 /* File handle. */
1049 +  };
1050
1051 +/* Open system call. */
1052 +static int
1053 +sys_open (const char *ufile) 
1054 +{
1055 +  char *kfile = copy_in_string (ufile);
1056 +  struct file_descriptor *fd;
1057 +  int handle = -1;
1058
1059 +  fd = malloc (sizeof *fd);
1060 +  if (fd != NULL)
1061 +    {
1062 +      fd->file = filesys_open (kfile);
1063 +      if (fd->file != NULL)
1064 +        {
1065 +          struct thread *cur = thread_current ();
1066 +          handle = fd->handle = cur->next_handle++;
1067 +          list_push_front (&cur->fds, &fd->elem);
1068 +        }
1069 +      else 
1070 +        free (fd);
1071 +    }
1072 +  
1073 +  palloc_free_page (kfile);
1074 +  return handle;
1075 +}
1076
1077 +/* Returns the file descriptor associated with the given handle.
1078 +   Terminates the process if HANDLE is not associated with an
1079 +   open file. */
1080 +static struct file_descriptor *
1081 +lookup_fd (int handle) 
1082 +{
1083 +  struct thread *cur = thread_current ();
1084 +  struct list_elem *e;
1085 +   
1086 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
1087 +       e = list_next (e))
1088 +    {
1089 +      struct file_descriptor *fd;
1090 +      fd = list_entry (e, struct file_descriptor, elem);
1091 +      if (fd->handle == handle)
1092 +        return fd;
1093 +    }
1094
1095 +  thread_exit ();
1096 +}
1097
1098 +/* Filesize system call. */
1099 +static int
1100 +sys_filesize (int handle) 
1101 +{
1102 +  struct file_descriptor *fd = lookup_fd (handle);
1103 +  int size;
1104
1105 +  size = file_length (fd->file);
1106
1107 +  return size;
1108 +}
1109
1110 +/* Read system call. */
1111 +static int
1112 +sys_read (int handle, void *udst_, unsigned size) 
1113  {
1114 -  printf ("system call!\n");
1115 +  uint8_t *udst = udst_;
1116 +  struct file_descriptor *fd;
1117 +  int bytes_read = 0;
1118 +
1119 +  /* Look up file descriptor. */
1120 +  if (handle != STDIN_FILENO)
1121 +    fd = lookup_fd (handle);
1122 +
1123 +  while (size > 0) 
1124 +    {
1125 +      /* How much to read into this page? */
1126 +      size_t page_left = PGSIZE - pg_ofs (udst);
1127 +      size_t read_amt = size < page_left ? size : page_left;
1128 +      off_t retval;
1129 +
1130 +      /* Check that touching this page is okay. */
1131 +      if (!page_lock (udst, true)) 
1132 +        thread_exit ();
1133 +
1134 +      /* Read from file into page. */
1135 +      if (handle != STDIN_FILENO) 
1136 +        {
1137 +          retval = file_read (fd->file, udst, read_amt);
1138 +          if (retval < 0)
1139 +            {
1140 +              if (bytes_read == 0)
1141 +                bytes_read = -1; 
1142 +              break;
1143 +            }
1144 +          bytes_read += retval; 
1145 +        }
1146 +      else 
1147 +        {
1148 +          size_t i;
1149 +          
1150 +          for (i = 0; i < read_amt; i++) 
1151 +            udst[i] = kbd_getc ();
1152 +          bytes_read = read_amt;
1153 +        }
1154 +
1155 +      /* Release page. */
1156 +      page_unlock (udst);
1157 +
1158 +      /* If it was a short read we're done. */
1159 +      if (retval != (off_t) read_amt)
1160 +        break;
1161 +
1162 +      /* Advance. */
1163 +      udst += retval;
1164 +      size -= retval;
1165 +    }
1166 +   
1167 +  return bytes_read;
1168 +}
1169
1170 +/* Write system call. */
1171 +static int
1172 +sys_write (int handle, void *usrc_, unsigned size) 
1173 +{
1174 +  uint8_t *usrc = usrc_;
1175 +  struct file_descriptor *fd = NULL;
1176 +  int bytes_written = 0;
1177 +
1178 +  /* Lookup up file descriptor. */
1179 +  if (handle != STDOUT_FILENO)
1180 +    fd = lookup_fd (handle);
1181 +
1182 +  while (size > 0) 
1183 +    {
1184 +      /* How much bytes to write to this page? */
1185 +      size_t page_left = PGSIZE - pg_ofs (usrc);
1186 +      size_t write_amt = size < page_left ? size : page_left;
1187 +      off_t retval;
1188 +
1189 +      /* Check that we can touch this user page. */
1190 +      if (!page_lock (usrc, false)) 
1191 +        thread_exit ();
1192 +
1193 +      /* Do the write. */
1194 +      if (handle == STDOUT_FILENO)
1195 +        {
1196 +          putbuf ((char *) usrc, write_amt);
1197 +          retval = write_amt;
1198 +        }
1199 +      else
1200 +        retval = file_write (fd->file, usrc, write_amt);
1201 +
1202 +      /* Release user page. */
1203 +      page_unlock (usrc);
1204 +
1205 +      /* Handle return value. */
1206 +      if (retval < 0) 
1207 +        {
1208 +          if (bytes_written == 0)
1209 +            bytes_written = -1;
1210 +          break;
1211 +        }
1212 +      bytes_written += retval;
1213 +
1214 +      /* If it was a short write we're done. */
1215 +      if (retval != (off_t) write_amt)
1216 +        break;
1217 +
1218 +      /* Advance. */
1219 +      usrc += retval;
1220 +      size -= retval;
1221 +    }
1222
1223 +  return bytes_written;
1224 +}
1225
1226 +/* Seek system call. */
1227 +static int
1228 +sys_seek (int handle, unsigned position) 
1229 +{
1230 +  if ((off_t) position >= 0)
1231 +    file_seek (lookup_fd (handle)->file, position);
1232 +  return 0;
1233 +}
1234
1235 +/* Tell system call. */
1236 +static int
1237 +sys_tell (int handle) 
1238 +{
1239 +  return file_tell (lookup_fd (handle)->file);
1240 +}
1241
1242 +/* Close system call. */
1243 +static int
1244 +sys_close (int handle) 
1245 +{
1246 +  struct file_descriptor *fd = lookup_fd (handle);
1247 +  file_close (fd->file);
1248 +  list_remove (&fd->elem);
1249 +  free (fd);
1250 +  return 0;
1251 +}
1252 +\f
1253 +/* Binds a mapping id to a region of memory and a file. */
1254 +struct mapping
1255 +  {
1256 +    struct list_elem elem;      /* List element. */
1257 +    int handle;                 /* Mapping id. */
1258 +    struct file *file;          /* File. */
1259 +    uint8_t *base;              /* Start of memory mapping. */
1260 +    size_t page_cnt;            /* Number of pages mapped. */
1261 +  };
1262 +
1263 +/* Returns the file descriptor associated with the given handle.
1264 +   Terminates the process if HANDLE is not associated with a
1265 +   memory mapping. */
1266 +static struct mapping *
1267 +lookup_mapping (int handle) 
1268 +{
1269 +  struct thread *cur = thread_current ();
1270 +  struct list_elem *e;
1271 +   
1272 +  for (e = list_begin (&cur->mappings); e != list_end (&cur->mappings);
1273 +       e = list_next (e))
1274 +    {
1275 +      struct mapping *m = list_entry (e, struct mapping, elem);
1276 +      if (m->handle == handle)
1277 +        return m;
1278 +    }
1279
1280    thread_exit ();
1281  }
1282 +
1283 +/* Remove mapping M from the virtual address space,
1284 +   writing back any pages that have changed. */
1285 +static void
1286 +unmap (struct mapping *m) 
1287 +{
1288 +  list_remove (&m->elem);
1289 +  while (m->page_cnt-- > 0) 
1290 +    {
1291 +      page_deallocate (m->base);
1292 +      m->base += PGSIZE;
1293 +    }
1294 +  file_close (m->file);
1295 +  free (m);
1296 +}
1297
1298 +/* Mmap system call. */
1299 +static int
1300 +sys_mmap (int handle, void *addr)
1301 +{
1302 +  struct file_descriptor *fd = lookup_fd (handle);
1303 +  struct mapping *m = malloc (sizeof *m);
1304 +  size_t offset;
1305 +  off_t length;
1306 +
1307 +  if (m == NULL || addr == NULL || pg_ofs (addr) != 0)
1308 +    return -1;
1309 +
1310 +  m->handle = thread_current ()->next_handle++;
1311 +  m->file = file_reopen (fd->file);
1312 +  if (m->file == NULL) 
1313 +    {
1314 +      free (m);
1315 +      return -1;
1316 +    }
1317 +  m->base = addr;
1318 +  m->page_cnt = 0;
1319 +  list_push_front (&thread_current ()->mappings, &m->elem);
1320 +
1321 +  offset = 0;
1322 +  length = file_length (m->file);
1323 +  while (length > 0)
1324 +    {
1325 +      struct page *p = page_allocate ((uint8_t *) addr + offset, false);
1326 +      if (p == NULL)
1327 +        {
1328 +          unmap (m);
1329 +          return -1;
1330 +        }
1331 +      p->private = false;
1332 +      p->file = m->file;
1333 +      p->file_offset = offset;
1334 +      p->file_bytes = length >= PGSIZE ? PGSIZE : length;
1335 +      offset += p->file_bytes;
1336 +      length -= p->file_bytes;
1337 +      m->page_cnt++;
1338 +    }
1339 +  
1340 +  return m->handle;
1341 +}
1342 +
1343 +/* Munmap system call. */
1344 +static int
1345 +sys_munmap (int mapping) 
1346 +{
1347 +  unmap (lookup_mapping (mapping));
1348 +  return 0;
1349 +}
1350 +\f 
1351 +/* On thread exit, close all open files and unmap all mappings. */
1352 +void
1353 +syscall_exit (void) 
1354 +{
1355 +  struct thread *cur = thread_current ();
1356 +  struct list_elem *e, *next;
1357 +   
1358 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
1359 +    {
1360 +      struct file_descriptor *fd = list_entry (e, struct file_descriptor, elem);
1361 +      next = list_next (e);
1362 +      file_close (fd->file);
1363 +      free (fd);
1364 +    }
1365 +   
1366 +  for (e = list_begin (&cur->mappings); e != list_end (&cur->mappings);
1367 +       e = next)
1368 +    {
1369 +      struct mapping *m = list_entry (e, struct mapping, elem);
1370 +      next = list_next (e);
1371 +      unmap (m);
1372 +    }
1373 +}
1374 Index: src/userprog/syscall.h
1375 diff -u src/userprog/syscall.h~ src/userprog/syscall.h
1376 --- src/userprog/syscall.h~ 2004-09-05 22:38:45.000000000 -0700
1377 +++ src/userprog/syscall.h 2006-04-08 18:52:50.000000000 -0700
1378 @@ -2,5 +2,6 @@
1379  #define USERPROG_SYSCALL_H
1380  
1381  void syscall_init (void);
1382 +void syscall_exit (void);
1383  
1384  #endif /* userprog/syscall.h */
1385 Index: src/vm/frame.c
1386 diff -u src/vm/frame.c~ src/vm/frame.c
1387 --- src/vm/frame.c~ 1969-12-31 16:00:00.000000000 -0800
1388 +++ src/vm/frame.c 2006-04-08 18:52:50.000000000 -0700
1389 @@ -0,0 +1,162 @@
1390 +#include "vm/frame.h"
1391 +#include <stdio.h>
1392 +#include "vm/page.h"
1393 +#include "devices/timer.h"
1394 +#include "threads/init.h"
1395 +#include "threads/malloc.h"
1396 +#include "threads/mmu.h"
1397 +#include "threads/palloc.h"
1398 +#include "threads/synch.h"
1399 +
1400 +static struct frame *frames;
1401 +static size_t frame_cnt;
1402 +
1403 +static struct lock scan_lock;
1404 +static size_t hand;
1405 +
1406 +/* Initialize the frame manager. */
1407 +void
1408 +frame_init (void) 
1409 +{
1410 +  void *base;
1411 +
1412 +  lock_init (&scan_lock);
1413 +  
1414 +  frames = malloc (sizeof *frames * ram_pages);
1415 +  if (frames == NULL)
1416 +    PANIC ("out of memory allocating page frames");
1417 +
1418 +  while ((base = palloc_get_page (PAL_USER)) != NULL) 
1419 +    {
1420 +      struct frame *f = &frames[frame_cnt++];
1421 +      lock_init (&f->lock);
1422 +      f->base = base;
1423 +      f->page = NULL;
1424 +    }
1425 +}
1426 +
1427 +/* Tries to allocate and lock a frame for PAGE.
1428 +   Returns the frame if successful, false on failure. */
1429 +static struct frame *
1430 +try_frame_alloc_and_lock (struct page *page) 
1431 +{
1432 +  size_t i;
1433 +
1434 +  lock_acquire (&scan_lock);
1435 +
1436 +  /* Find a free frame. */
1437 +  for (i = 0; i < frame_cnt; i++)
1438 +    {
1439 +      struct frame *f = &frames[i];
1440 +      if (!lock_try_acquire (&f->lock))
1441 +        continue;
1442 +      if (f->page == NULL) 
1443 +        {
1444 +          f->page = page;
1445 +          lock_release (&scan_lock);
1446 +          return f;
1447 +        } 
1448 +      lock_release (&f->lock);
1449 +    }
1450 +
1451 +  /* No free frame.  Find a frame to evict. */
1452 +  for (i = 0; i < frame_cnt * 2; i++) 
1453 +    {
1454 +      /* Get a frame. */
1455 +      struct frame *f = &frames[hand];
1456 +      if (++hand >= frame_cnt)
1457 +        hand = 0;
1458 +
1459 +      if (!lock_try_acquire (&f->lock))
1460 +        continue;
1461 +
1462 +      if (f->page == NULL) 
1463 +        {
1464 +          f->page = page;
1465 +          lock_release (&scan_lock);
1466 +          return f;
1467 +        } 
1468 +
1469 +      if (page_accessed_recently (f->page)) 
1470 +        {
1471 +          lock_release (&f->lock);
1472 +          continue;
1473 +        }
1474 +          
1475 +      lock_release (&scan_lock);
1476 +      
1477 +      /* Evict this frame. */
1478 +      if (!page_out (f->page))
1479 +        {
1480 +          lock_release (&f->lock);
1481 +          return NULL;
1482 +        }
1483 +
1484 +      f->page = page;
1485 +      return f;
1486 +    }
1487 +
1488 +  lock_release (&scan_lock);
1489 +  return NULL;
1490 +}
1491 +
1492 +
1493 +/* Tries really hard to allocate and lock a frame for PAGE.
1494 +   Returns the frame if successful, false on failure. */
1495 +struct frame *
1496 +frame_alloc_and_lock (struct page *page) 
1497 +{
1498 +  size_t try;
1499 +
1500 +  for (try = 0; try < 3; try++) 
1501 +    {
1502 +      struct frame *f = try_frame_alloc_and_lock (page);
1503 +      if (f != NULL) 
1504 +        {
1505 +          ASSERT (lock_held_by_current_thread (&f->lock));
1506 +          return f; 
1507 +        }
1508 +      timer_msleep (1000);
1509 +    }
1510 +
1511 +  return NULL;
1512 +}
1513 +
1514 +/* Locks P's frame into memory, if it has one.
1515 +   Upon return, p->frame will not change until P is unlocked. */
1516 +void
1517 +frame_lock (struct page *p) 
1518 +{
1519 +  /* A frame can be asynchronously removed, but never inserted. */
1520 +  struct frame *f = p->frame;
1521 +  if (f != NULL) 
1522 +    {
1523 +      lock_acquire (&f->lock);
1524 +      if (f != p->frame)
1525 +        {
1526 +          lock_release (&f->lock);
1527 +          ASSERT (p->frame == NULL); 
1528 +        } 
1529 +    }
1530 +}
1531 +
1532 +/* Releases frame F for use by another page.
1533 +   F must be locked for use by the current process.
1534 +   Any data in F is lost. */
1535 +void
1536 +frame_free (struct frame *f)
1537 +{
1538 +  ASSERT (lock_held_by_current_thread (&f->lock));
1539 +          
1540 +  f->page = NULL;
1541 +  lock_release (&f->lock);
1542 +}
1543 +
1544 +/* Unlocks frame F, allowing it to be evicted.
1545 +   F must be locked for use by the current process. */
1546 +void
1547 +frame_unlock (struct frame *f) 
1548 +{
1549 +  ASSERT (lock_held_by_current_thread (&f->lock));
1550 +  lock_release (&f->lock);
1551 +}
1552 Index: src/vm/frame.h
1553 diff -u src/vm/frame.h~ src/vm/frame.h
1554 --- src/vm/frame.h~ 1969-12-31 16:00:00.000000000 -0800
1555 +++ src/vm/frame.h 2006-04-08 18:52:50.000000000 -0700
1556 @@ -0,0 +1,23 @@
1557 +#ifndef VM_FRAME_H
1558 +#define VM_FRAME_H
1559 +
1560 +#include <stdbool.h>
1561 +#include "threads/synch.h"
1562 +
1563 +/* A physical frame. */
1564 +struct frame 
1565 +  {
1566 +    struct lock lock;           /* Prevent simultaneous access. */
1567 +    void *base;                 /* Kernel virtual base address. */
1568 +    struct page *page;          /* Mapped process page, if any. */
1569 +  };
1570 +
1571 +void frame_init (void);
1572 +
1573 +struct frame *frame_alloc_and_lock (struct page *);
1574 +void frame_lock (struct page *);
1575 +
1576 +void frame_free (struct frame *);
1577 +void frame_unlock (struct frame *);
1578 +
1579 +#endif /* vm/frame.h */
1580 Index: src/vm/page.c
1581 diff -u src/vm/page.c~ src/vm/page.c
1582 --- src/vm/page.c~ 1969-12-31 16:00:00.000000000 -0800
1583 +++ src/vm/page.c 2006-04-08 18:52:50.000000000 -0700
1584 @@ -0,0 +1,293 @@
1585 +#include "vm/page.h"
1586 +#include <stdio.h>
1587 +#include <string.h>
1588 +#include "vm/frame.h"
1589 +#include "vm/swap.h"
1590 +#include "filesys/file.h"
1591 +#include "threads/malloc.h"
1592 +#include "threads/mmu.h"
1593 +#include "threads/thread.h"
1594 +#include "userprog/pagedir.h"
1595 +
1596 +/* Maximum size of process stack, in bytes. */
1597 +#define STACK_MAX (1024 * 1024)
1598 +
1599 +/* Destroys a page, which must be in the current process's
1600 +   page table.  Used as a callback for hash_destroy(). */
1601 +static void
1602 +destroy_page (struct hash_elem *p_, void *aux UNUSED)
1603 +{
1604 +  struct page *p = hash_entry (p_, struct page, hash_elem);
1605 +  frame_lock (p);
1606 +  if (p->frame)
1607 +    frame_free (p->frame);
1608 +  free (p);
1609 +}
1610 +
1611 +/* Destroys the current process's page table. */
1612 +void
1613 +page_exit (void) 
1614 +{
1615 +  struct hash *h = thread_current ()->pages;
1616 +  if (h != NULL)
1617 +    hash_destroy (h, destroy_page);
1618 +}
1619 +
1620 +/* Returns the page containing the given virtual ADDRESS,
1621 +   or a null pointer if no such page exists.
1622 +   Allocates stack pages as necessary. */
1623 +static struct page *
1624 +page_for_addr (const void *address) 
1625 +{
1626 +  if (address < PHYS_BASE) 
1627 +    {
1628 +      struct page p;
1629 +      struct hash_elem *e;
1630 +
1631 +      /* Find existing page. */
1632 +      p.addr = (void *) pg_round_down (address);
1633 +      e = hash_find (thread_current ()->pages, &p.hash_elem);
1634 +      if (e != NULL)
1635 +        return hash_entry (e, struct page, hash_elem);
1636 +
1637 +      /* No page.  Expand stack? */
1638 +      if (address >= PHYS_BASE - STACK_MAX
1639 +          && address >= thread_current ()->user_esp - 32)
1640 +        return page_allocate ((void *) address, false);
1641 +    }
1642 +  return NULL;
1643 +}
1644 +
1645 +/* Locks a frame for page P and pages it in.
1646 +   Returns true if successful, false on failure. */
1647 +static bool
1648 +do_page_in (struct page *p)
1649 +{
1650 +  /* Get a frame for the page. */
1651 +  p->frame = frame_alloc_and_lock (p);
1652 +  if (p->frame == NULL)
1653 +    return false;
1654 +
1655 +  /* Copy data into the frame. */
1656 +  if (p->sector != (disk_sector_t) -1) 
1657 +    {
1658 +      /* Get data from swap. */
1659 +      swap_in (p); 
1660 +    }
1661 +  else if (p->file != NULL) 
1662 +    {
1663 +      /* Get data from file. */
1664 +      off_t read_bytes = file_read_at (p->file, p->frame->base,
1665 +                                        p->file_bytes, p->file_offset);
1666 +      off_t zero_bytes = PGSIZE - read_bytes;
1667 +      memset (p->frame->base + read_bytes, 0, zero_bytes);
1668 +      if (read_bytes != p->file_bytes)
1669 +        printf ("bytes read (%"PROTd") != bytes requested (%"PROTd")\n",
1670 +                read_bytes, p->file_bytes);
1671 +    }
1672 +  else 
1673 +    {
1674 +      /* Provide all-zero page. */
1675 +      memset (p->frame->base, 0, PGSIZE);
1676 +    }
1677 +
1678 +  return true;
1679 +}
1680 +
1681 +/* Faults in the page containing FAULT_ADDR.
1682 +   Returns true if successful, false on failure. */
1683 +bool
1684 +page_in (void *fault_addr) 
1685 +{
1686 +  struct page *p;
1687 +  bool success;
1688 +
1689 +  /* Can't handle page faults without a hash table. */
1690 +  if (thread_current ()->pages == NULL) 
1691 +    return false;
1692 +
1693 +  p = page_for_addr (fault_addr);
1694 +  if (p == NULL) 
1695 +    return false; 
1696 +
1697 +  frame_lock (p);
1698 +  if (p->frame == NULL)
1699 +    {
1700 +      if (!do_page_in (p))
1701 +        return false;
1702 +    }
1703 +  ASSERT (lock_held_by_current_thread (&p->frame->lock));
1704 +    
1705 +  /* Install frame into page table. */
1706 +  success = pagedir_set_page (thread_current ()->pagedir, p->addr,
1707 +                              p->frame->base, !p->read_only);
1708 +
1709 +  /* Release frame. */
1710 +  frame_unlock (p->frame);
1711 +
1712 +  return success;
1713 +}
1714 +
1715 +/* Evicts page P.
1716 +   P must have a locked frame.
1717 +   Return true if successful, false on failure. */
1718 +bool
1719 +page_out (struct page *p) 
1720 +{
1721 +  bool dirty;
1722 +  bool ok;
1723 +
1724 +  ASSERT (p->frame != NULL);
1725 +  ASSERT (lock_held_by_current_thread (&p->frame->lock));
1726 +
1727 +  /* Mark page not present in page table, forcing accesses by the
1728 +     process to fault.  This must happen before checking the
1729 +     dirty bit, to prevent a race with the process dirtying the
1730 +     page. */
1731 +  pagedir_clear_page (p->thread->pagedir, p->addr);
1732 +
1733 +  /* Has the frame been modified? */
1734 +  dirty = pagedir_is_dirty (p->thread->pagedir, p->addr);
1735 +
1736 +  /* Write frame contents to disk if necessary. */
1737 +  if (p->file != NULL) 
1738 +    {
1739 +      if (dirty) 
1740 +        {
1741 +          if (p->private)
1742 +            ok = swap_out (p);
1743 +          else 
1744 +            ok = file_write_at (p->file, p->frame->base, p->file_bytes,
1745 +                                p->file_offset) == p->file_bytes;
1746 +        }
1747 +      else
1748 +        ok = true;
1749 +    }
1750 +  else
1751 +    ok = swap_out (p);
1752 +  if (ok) 
1753 +    {
1754 +      //memset (p->frame->base, 0xcc, PGSIZE);
1755 +      p->frame = NULL; 
1756 +    }
1757 +  return ok;
1758 +}
1759 +
1760 +/* Returns true if page P's data has been accessed recently,
1761 +   false otherwise.
1762 +   P must have a frame locked into memory. */
1763 +bool
1764 +page_accessed_recently (struct page *p) 
1765 +{
1766 +  bool was_accessed;
1767 +
1768 +  ASSERT (p->frame != NULL);
1769 +  ASSERT (lock_held_by_current_thread (&p->frame->lock));
1770 +
1771 +  was_accessed = pagedir_is_accessed (p->thread->pagedir, p->addr);
1772 +  if (was_accessed)
1773 +    pagedir_set_accessed (p->thread->pagedir, p->addr, false);
1774 +  return was_accessed;
1775 +}
1776 +
1777 +/* Adds a mapping for user virtual address VADDR to the page hash
1778 +   table.  Fails if VADDR is already mapped or if memory
1779 +   allocation fails. */
1780 +struct page *
1781 +page_allocate (void *vaddr, bool read_only)
1782 +{
1783 +  struct thread *t = thread_current ();
1784 +  struct page *p = malloc (sizeof *p);
1785 +  if (p != NULL) 
1786 +    {
1787 +      p->addr = pg_round_down (vaddr);
1788 +
1789 +      p->read_only = read_only;
1790 +      p->private = !read_only;
1791 +
1792 +      p->frame = NULL;
1793 +
1794 +      p->sector = (disk_sector_t) -1;
1795 +
1796 +      p->file = NULL;
1797 +      p->file_offset = 0;
1798 +      p->file_bytes = 0;
1799 +
1800 +      p->thread = thread_current ();
1801 +
1802 +      if (hash_insert (t->pages, &p->hash_elem) != NULL) 
1803 +        {
1804 +          /* Already mapped. */
1805 +          free (p);
1806 +          p = NULL;
1807 +        }
1808 +    }
1809 +  return p;
1810 +}
1811 +
1812 +/* Evicts the page containing address VADDR
1813 +   and removes it from the page table. */
1814 +void
1815 +page_deallocate (void *vaddr) 
1816 +{
1817 +  struct page *p = page_for_addr (vaddr);
1818 +  ASSERT (p != NULL);
1819 +  frame_lock (p);
1820 +  if (p->frame)
1821 +    {
1822 +      struct frame *f = p->frame;
1823 +      if (p->file && !p->private) 
1824 +        page_out (p); 
1825 +      frame_free (f);
1826 +    }
1827 +  hash_delete (thread_current ()->pages, &p->hash_elem);
1828 +  free (p);
1829 +}
1830 +
1831 +/* Returns a hash value for the page that E refers to. */
1832 +unsigned
1833 +page_hash (const struct hash_elem *e, void *aux UNUSED) 
1834 +{
1835 +  const struct page *p = hash_entry (e, struct page, hash_elem);
1836 +  return ((uintptr_t) p->addr) >> PGBITS;
1837 +}
1838 +
1839 +/* Returns true if page A precedes page B. */
1840 +bool
1841 +page_less (const struct hash_elem *a_, const struct hash_elem *b_,
1842 +           void *aux UNUSED) 
1843 +{
1844 +  const struct page *a = hash_entry (a_, struct page, hash_elem);
1845 +  const struct page *b = hash_entry (b_, struct page, hash_elem);
1846 +  
1847 +  return a->addr < b->addr;
1848 +}
1849 +
1850 +/* Tries to lock the page containing ADDR into physical memory.
1851 +   If WILL_WRITE is true, the page must be writeable;
1852 +   otherwise it may be read-only.
1853 +   Returns true if successful, false on failure. */
1854 +bool
1855 +page_lock (const void *addr, bool will_write) 
1856 +{
1857 +  struct page *p = page_for_addr (addr);
1858 +  if (p == NULL || (p->read_only && will_write))
1859 +    return false;
1860 +  
1861 +  frame_lock (p);
1862 +  if (p->frame == NULL)
1863 +    return (do_page_in (p)
1864 +            && pagedir_set_page (thread_current ()->pagedir, p->addr,
1865 +                                 p->frame->base, !p->read_only)); 
1866 +  else
1867 +    return true;
1868 +}
1869 +
1870 +/* Unlocks a page locked with page_lock(). */
1871 +void
1872 +page_unlock (const void *addr) 
1873 +{
1874 +  struct page *p = page_for_addr (addr);
1875 +  ASSERT (p != NULL);
1876 +  frame_unlock (p->frame);
1877 +}
1878 Index: src/vm/page.h
1879 diff -u src/vm/page.h~ src/vm/page.h
1880 --- src/vm/page.h~ 1969-12-31 16:00:00.000000000 -0800
1881 +++ src/vm/page.h 2006-04-08 18:52:50.000000000 -0700
1882 @@ -0,0 +1,50 @@
1883 +#ifndef VM_PAGE_H
1884 +#define VM_PAGE_H
1885 +
1886 +#include <hash.h>
1887 +#include "devices/disk.h"
1888 +#include "filesys/off_t.h"
1889 +#include "threads/synch.h"
1890 +
1891 +/* Virtual page. */
1892 +struct page 
1893 +  {
1894 +    /* Immutable members. */
1895 +    void *addr;                 /* User virtual address. */
1896 +    bool read_only;             /* Read-only page? */
1897 +    struct thread *thread;      /* Owning thread. */
1898 +
1899 +    /* Accessed only in owning process context. */
1900 +    struct hash_elem hash_elem; /* struct thread `pages' hash element. */
1901 +
1902 +    /* Set only in owning process context with frame->frame_lock held.
1903 +       Cleared only with scan_lock and frame->frame_lock held. */
1904 +    struct frame *frame;        /* Page frame. */
1905 +
1906 +    /* Swap information, protected by frame->frame_lock. */
1907 +    disk_sector_t sector;       /* Starting sector of swap area, or -1. */
1908 +    
1909 +    /* Memory-mapped file information, protected by frame->frame_lock. */
1910 +    bool private;               /* False to write back to file,
1911 +                                   true to write back to swap. */
1912 +    struct file *file;          /* File. */
1913 +    off_t file_offset;          /* Offset in file. */
1914 +    off_t file_bytes;           /* Bytes to read/write, 1...PGSIZE. */
1915 +  };
1916 +
1917 +void page_exit (void);
1918 +
1919 +struct page *page_allocate (void *, bool read_only);
1920 +void page_deallocate (void *vaddr);
1921 +
1922 +bool page_in (void *fault_addr);
1923 +bool page_out (struct page *);
1924 +bool page_accessed_recently (struct page *);
1925 +
1926 +bool page_lock (const void *, bool will_write);
1927 +void page_unlock (const void *);
1928 +
1929 +hash_hash_func page_hash;
1930 +hash_less_func page_less;
1931 +
1932 +#endif /* vm/page.h */
1933 Index: src/vm/swap.c
1934 diff -u src/vm/swap.c~ src/vm/swap.c
1935 --- src/vm/swap.c~ 1969-12-31 16:00:00.000000000 -0800
1936 +++ src/vm/swap.c 2006-04-08 18:52:50.000000000 -0700
1937 @@ -0,0 +1,85 @@
1938 +#include "vm/swap.h"
1939 +#include <bitmap.h>
1940 +#include <debug.h>
1941 +#include <stdio.h>
1942 +#include "vm/frame.h"
1943 +#include "vm/page.h"
1944 +#include "devices/disk.h"
1945 +#include "threads/mmu.h"
1946 +#include "threads/synch.h"
1947 +
1948 +/* The swap disk. */
1949 +static struct disk *swap_disk;
1950 +
1951 +/* Used swap pages. */
1952 +static struct bitmap *swap_bitmap;
1953 +
1954 +/* Protects swap_bitmap. */
1955 +static struct lock swap_lock;
1956 +
1957 +/* Number of sectors per page. */
1958 +#define PAGE_SECTORS (PGSIZE / DISK_SECTOR_SIZE)
1959 +
1960 +/* Sets up swap. */
1961 +void
1962 +swap_init (void) 
1963 +{
1964 +  swap_disk = disk_get (1, 1);
1965 +  if (swap_disk == NULL) 
1966 +    {
1967 +      printf ("no swap disk--swap disabled\n");
1968 +      swap_bitmap = bitmap_create (0);
1969 +    }
1970 +  else
1971 +    swap_bitmap = bitmap_create (disk_size (swap_disk) / PAGE_SECTORS);
1972 +  if (swap_bitmap == NULL)
1973 +    PANIC ("couldn't create swap bitmap");
1974 +  lock_init (&swap_lock);
1975 +}
1976 +
1977 +/* Swaps in page P, which must have a locked frame
1978 +   (and be swapped out). */
1979 +void
1980 +swap_in (struct page *p) 
1981 +{
1982 +  size_t i;
1983 +  
1984 +  ASSERT (p->frame != NULL);
1985 +  ASSERT (lock_held_by_current_thread (&p->frame->lock));
1986 +  ASSERT (p->sector != (disk_sector_t) -1);
1987 +
1988 +  for (i = 0; i < PAGE_SECTORS; i++)
1989 +    disk_read (swap_disk, p->sector + i,
1990 +               p->frame->base + i * DISK_SECTOR_SIZE);
1991 +  bitmap_reset (swap_bitmap, p->sector / PAGE_SECTORS);
1992 +  p->sector = (disk_sector_t) -1;
1993 +}
1994 +
1995 +/* Swaps out page P, which must have a locked frame. */
1996 +bool
1997 +swap_out (struct page *p) 
1998 +{
1999 +  size_t slot;
2000 +  size_t i;
2001 +
2002 +  ASSERT (p->frame != NULL);
2003 +  ASSERT (lock_held_by_current_thread (&p->frame->lock));
2004 +
2005 +  lock_acquire (&swap_lock);
2006 +  slot = bitmap_scan_and_flip (swap_bitmap, 0, 1, false);
2007 +  lock_release (&swap_lock);
2008 +  if (slot == BITMAP_ERROR) 
2009 +    return false; 
2010 +
2011 +  p->sector = slot * PAGE_SECTORS;
2012 +  for (i = 0; i < PAGE_SECTORS; i++)
2013 +    disk_write (swap_disk, p->sector + i,
2014 +                p->frame->base + i * DISK_SECTOR_SIZE);
2015 +  
2016 +  p->private = false;
2017 +  p->file = NULL;
2018 +  p->file_offset = 0;
2019 +  p->file_bytes = 0;
2020 +
2021 +  return true;
2022 +}
2023 Index: src/vm/swap.h
2024 diff -u src/vm/swap.h~ src/vm/swap.h
2025 --- src/vm/swap.h~ 1969-12-31 16:00:00.000000000 -0800
2026 +++ src/vm/swap.h 2006-04-08 18:52:50.000000000 -0700
2027 @@ -0,0 +1,11 @@
2028 +#ifndef VM_SWAP_H
2029 +#define VM_SWAP_H 1
2030 +
2031 +#include <stdbool.h>
2032 +
2033 +struct page;
2034 +void swap_init (void);
2035 +void swap_in (struct page *);
2036 +bool swap_out (struct page *);
2037 +
2038 +#endif /* vm/swap.h */