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