Make solutions apply again.
[pintos-anon] / solutions / p2.patch
1 Index: src/threads/thread.c
2 diff -u src/threads/thread.c~ src/threads/thread.c
3 --- src/threads/thread.c~
4 +++ src/threads/thread.c
5 @@ -13,6 +13,7 @@
6  #include "threads/synch.h"
7  #ifdef USERPROG
8  #include "userprog/process.h"
9 +#include "userprog/syscall.h"
10  #endif
11  
12  /* Random value for struct thread's `magic' member.
13 @@ -251,16 +252,19 @@ thread_tid (void) 
14  void
15  thread_exit (void) 
16  {
17 +  struct thread *t = thread_current ();
18 +
19    ASSERT (!intr_context ());
20  
21  #ifdef USERPROG
22    process_exit ();
23  #endif
24 -
25 +  syscall_exit ();
26 +  
27    /* Just set our status to dying and schedule another process.
28       We will be destroyed during the call to schedule_tail(). */
29    intr_disable ();
30 -  thread_current ()->status = THREAD_DYING;
31 +  t->status = THREAD_DYING;
32    schedule ();
33    NOT_REACHED ();
34  }
35 @@ -400,6 +404,10 @@ init_thread (struct thread *t, const cha
36    strlcpy (t->name, name, sizeof t->name);
37    t->stack = (uint8_t *) t + PGSIZE;
38    t->priority = priority;
39 +  list_init (&t->children);
40 +  t->wait_status = NULL;
41 +  list_init (&t->fds);
42 +  t->next_handle = 2;
43    t->magic = THREAD_MAGIC;
44  }
45  
46 Index: src/threads/thread.h
47 diff -u src/threads/thread.h~ src/threads/thread.h
48 --- src/threads/thread.h~
49 +++ src/threads/thread.h
50 @@ -4,6 +4,7 @@
51  #include <debug.h>
52  #include <list.h>
53  #include <stdint.h>
54 +#include "threads/synch.h"
55  
56  /* States in a thread's life cycle. */
57  enum thread_status
58 @@ -89,6 +90,10 @@ struct thread
59      uint8_t *stack;                     /* Saved stack pointer. */
60      int priority;                       /* Priority. */
61  
62 +    /* Owned by process.c. */
63 +    struct wait_status *wait_status;    /* This process's completion status. */
64 +    struct list children;               /* Completion status of children. */
65 +
66      /* Shared between thread.c and synch.c. */
67      struct list_elem elem;              /* List element. */
68  
69 @@ -96,11 +102,31 @@ struct thread
70      /* Owned by userprog/process.c. */
71      uint32_t *pagedir;                  /* Page directory. */
72  #endif
73 +    struct file *bin_file;              /* Executable. */
74 +
75 +    /* Owned by syscall.c. */
76 +    struct list fds;                    /* List of file descriptors. */
77 +    int next_handle;                    /* Next handle value. */
78  
79      /* Owned by thread.c. */
80      unsigned magic;                     /* Detects stack overflow. */
81    };
82  
83 +/* Tracks the completion of a process.
84 +   Reference held by both the parent, in its `children' list,
85 +   and by the child, in its `wait_status' pointer. */
86 +struct wait_status
87 +  {
88 +    struct list_elem elem;              /* `children' list element. */
89 +    struct lock lock;                   /* Protects ref_cnt. */
90 +    int ref_cnt;                        /* 2=child and parent both alive,
91 +                                           1=either child or parent alive,
92 +                                           0=child and parent both dead. */
93 +    tid_t tid;                          /* Child thread id. */
94 +    int exit_code;                      /* Child exit code, if dead. */
95 +    struct semaphore dead;              /* 1=child alive, 0=child dead. */
96 +  };
97 +
98  /* If false (default), use round-robin scheduler.
99     If true, use multi-level feedback queue scheduler.
100     Controlled by kernel command-line options "-o mlfqs".
101 Index: src/userprog/exception.c
102 diff -u src/userprog/exception.c~ src/userprog/exception.c
103 --- src/userprog/exception.c~
104 +++ src/userprog/exception.c
105 @@ -150,6 +150,14 @@ page_fault (struct intr_frame *f) 
106    write = (f->error_code & PF_W) != 0;
107    user = (f->error_code & PF_U) != 0;
108  
109 +  /* Handle bad dereferences from system call implementations. */
110 +  if (!user) 
111 +    {
112 +      f->eip = (void (*) (void)) f->eax;
113 +      f->eax = 0;
114 +      return;
115 +    }
116 +
117    /* To implement virtual memory, delete the rest of the function
118       body, and replace it with code that brings in the page to
119       which fault_addr refers. */
120 Index: src/userprog/process.c
121 diff -u src/userprog/process.c~ src/userprog/process.c
122 --- src/userprog/process.c~
123 +++ src/userprog/process.c
124 @@ -14,11 +14,23 @@
125  #include "threads/init.h"
126  #include "threads/interrupt.h"
127 +#include "threads/malloc.h"
128  #include "threads/palloc.h"
129  #include "threads/thread.h"
130  #include "threads/vaddr.h"
131  
132  static thread_func execute_thread NO_RETURN;
133 -static bool load (const char *cmdline, void (**eip) (void), void **esp);
134 +static bool load (const char *cmd_line, void (**eip) (void), void **esp);
135 +
136 +/* Data structure shared between process_execute() in the
137 +   invoking thread and execute_thread() in the newly invoked
138 +   thread. */
139 +struct exec_info 
140 +  {
141 +    const char *file_name;              /* Program to load. */
142 +    struct semaphore load_done;         /* "Up"ed when loading complete. */
143 +    struct wait_status *wait_status;    /* Child process. */
144 +    bool success;                       /* Program successfully loaded? */
145 +  };
146  
147  /* Starts a new thread running a user program loaded from
148     FILE_NAME.  The new thread may be scheduled (and may even exit)
149 @@ -27,29 +39,37 @@ static bool load (const char *cmdline, v
150  tid_t
151  process_execute (const char *file_name) 
152  {
153 -  char *fn_copy;
154 +  struct exec_info exec;
155 +  char thread_name[16];
156 +  char *save_ptr;
157    tid_t tid;
158  
159 -  /* Make a copy of FILE_NAME.
160 -     Otherwise there's a race between the caller and load(). */
161 -  fn_copy = palloc_get_page (0);
162 -  if (fn_copy == NULL)
163 -    return TID_ERROR;
164 -  strlcpy (fn_copy, file_name, PGSIZE);
165 +  /* Initialize exec_info. */
166 +  exec.file_name = file_name;
167 +  sema_init (&exec.load_done, 0);
168  
169    /* Create a new thread to execute FILE_NAME. */
170 -  tid = thread_create (file_name, PRI_DEFAULT, execute_thread, fn_copy);
171 -  if (tid == TID_ERROR)
172 -    palloc_free_page (fn_copy); 
173 +  strlcpy (thread_name, file_name, sizeof thread_name);
174 +  strtok_r (thread_name, " ", &save_ptr);
175 +  tid = thread_create (thread_name, PRI_DEFAULT, execute_thread, &exec);
176 +  if (tid != TID_ERROR)
177 +    {
178 +      sema_down (&exec.load_done);
179 +      if (exec.success)
180 +        list_push_back (&thread_current ()->children, &exec.wait_status->elem);
181 +      else
182 +        tid = TID_ERROR;
183 +    }
184 +
185    return tid;
186  }
187  
188  /* A thread function that loads a user process and starts it
189     running. */
190  static void
191 -execute_thread (void *file_name_)
192 +execute_thread (void *exec_)
193  {
194 -  char *file_name = file_name_;
195 +  struct exec_info *exec = exec_;
196    struct intr_frame if_;
197    bool success;
198  
199 @@ -58,10 +78,29 @@ execute_thread (void *file_name_)
200    if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
201    if_.cs = SEL_UCSEG;
202    if_.eflags = FLAG_IF | FLAG_MBS;
203 -  success = load (file_name, &if_.eip, &if_.esp);
204 +  success = load (exec->file_name, &if_.eip, &if_.esp);
205 +
206 +  /* Allocate wait_status. */
207 +  if (success)
208 +    {
209 +      exec->wait_status = thread_current ()->wait_status
210 +        = malloc (sizeof *exec->wait_status);
211 +      success = exec->wait_status != NULL; 
212 +    }
213  
214 -  /* If load failed, quit. */
215 -  palloc_free_page (file_name);
216 +  /* Initialize wait_status. */
217 +  if (success) 
218 +    {
219 +      lock_init (&exec->wait_status->lock);
220 +      exec->wait_status->ref_cnt = 2;
221 +      exec->wait_status->tid = thread_current ()->tid;
222 +      exec->wait_status->exit_code = -1;
223 +      sema_init (&exec->wait_status->dead, 0);
224 +    }
225 +  
226 +  /* Notify parent thread and clean up. */
227 +  exec->success = success;
228 +  sema_up (&exec->load_done);
229    if (!success) 
230      thread_exit ();
231  
232 @@ -75,18 +113,47 @@ execute_thread (void *file_name_)
233    NOT_REACHED ();
234  }
235  
236 +/* Releases one reference to CS and, if it is now unreferenced,
237 +   frees it. */
238 +static void
239 +release_child (struct wait_status *cs) 
240 +{
241 +  int new_ref_cnt;
242 +  
243 +  lock_acquire (&cs->lock);
244 +  new_ref_cnt = --cs->ref_cnt;
245 +  lock_release (&cs->lock);
246 +
247 +  if (new_ref_cnt == 0)
248 +    free (cs);
249 +}
250 +
251  /* Waits for thread TID to die and returns its exit status.  If
252     it was terminated by the kernel (i.e. killed due to an
253     exception), returns -1.  If TID is invalid or if it was not a
254     child of the calling process, or if process_wait() has already
255     been successfully called for the given TID, returns -1
256 -   immediately, without waiting.
257 -
258 -   This function will be implemented in problem 2-2.  For now, it
259 -   does nothing. */
260 +   immediately, without waiting. */
261  int
262 -process_wait (tid_t child_tid UNUSED) 
263 +process_wait (tid_t child_tid) 
264  {
265 +  struct thread *cur = thread_current ();
266 +  struct list_elem *e;
267 +
268 +  for (e = list_begin (&cur->children); e != list_end (&cur->children);
269 +       e = list_next (e)) 
270 +    {
271 +      struct wait_status *cs = list_entry (e, struct wait_status, elem);
272 +      if (cs->tid == child_tid) 
273 +        {
274 +          int exit_code;
275 +          list_remove (e);
276 +          sema_down (&cs->dead);
277 +          exit_code = cs->exit_code;
278 +          release_child (cs);
279 +          return exit_code;
280 +        }
281 +    }
282    return -1;
283  }
284  
285 @@ -95,8 +162,30 @@ void
286  process_exit (void)
287  {
288    struct thread *cur = thread_current ();
289 +  struct list_elem *e, *next;
290    uint32_t *pd;
291  
292 +  /* Close executable (and allow writes). */
293 +  file_close (cur->bin_file);
294 +
295 +  /* Notify parent that we're dead. */
296 +  if (cur->wait_status != NULL) 
297 +    {
298 +      struct wait_status *cs = cur->wait_status;
299 +      printf ("%s: exit(%d)\n", cur->name, cs->exit_code);
300 +      sema_up (&cs->dead);
301 +      release_child (cs);
302 +    }
303 +
304 +  /* Free entries of children list. */
305 +  for (e = list_begin (&cur->children); e != list_end (&cur->children);
306 +       e = next) 
307 +    {
308 +      struct wait_status *cs = list_entry (e, struct wait_status, elem);
309 +      next = list_remove (e);
310 +      release_child (cs);
311 +    }
312 +  
313    /* Destroy the current process's page directory and switch back
314       to the kernel-only page directory. */
315    pd = cur->pagedir;
316 @@ -193,7 +284,7 @@ struct Elf32_Phdr
317  #define PF_W 2          /* Writable. */
318  #define PF_R 4          /* Readable. */
319  
320 -static bool setup_stack (void **esp);
321 +static bool setup_stack (const char *cmd_line, void **esp);
322  static bool validate_segment (const struct Elf32_Phdr *, struct file *);
323  static bool load_segment (struct file *file, off_t ofs, uint8_t *upage,
324                            bool writable);
325 @@ -209,13 +300,15 @@ static bool setup_stack (void **esp);
326     and its initial stack pointer into *ESP.
327     Returns true if successful, false otherwise. */
328  bool
329 -load (const char *file_name, void (**eip) (void), void **esp) 
330 +load (const char *cmd_line, void (**eip) (void), void **esp) 
331  {
332    struct thread *t = thread_current ();
333 +  char file_name[NAME_MAX + 2];
334    struct Elf32_Ehdr ehdr;
335    struct file *file = NULL;
336    off_t file_ofs;
337    bool success = false;
338 +  char *cp;
339    int i;
340  
341    /* Allocate and activate page directory. */
342 @@ -224,13 +317,22 @@ load (const char *file_name, void (**eip)
343      goto done;
344    process_activate ();
345  
346 +  /* Extract file_name from command line. */
347 +  while (*cmd_line == ' ')
348 +    cmd_line++;
349 +  strlcpy (file_name, cmd_line, sizeof file_name);
350 +  cp = strchr (file_name, ' ');
351 +  if (cp != NULL)
352 +    *cp = '\0';
353 +
354    /* Open executable file. */
355 -  file = filesys_open (file_name);
356 +  t->bin_file = file = filesys_open (file_name);
357    if (file == NULL) 
358      {
359        printf ("load: %s: open failed\n", file_name);
360        goto done; 
361      }
362 +  file_deny_write (file);
363  
364    /* Read and verify executable header. */
365    if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr
366 @@ -284,7 +386,7 @@ load (const char *file_name, void (**eip)
367      }
368  
369    /* Set up stack. */
370 -  if (!setup_stack (esp))
371 +  if (!setup_stack (cmd_line, esp))
372      goto done;
373  
374    /* Start address. */
375 @@ -294,7 +396,6 @@ load (const char *file_name, void (**eip)
376  
377   done:
378    /* We arrive here whether the load is successful or not. */
379 -  file_close (file);
380    return success;
381  }
382  \f
383 @@ -393,10 +494,92 @@ load_segment (struct file *file, const s
384    return true;
385  }
386  
387 -/* Create a minimal stack by mapping a zeroed page at the top of
388 -   user virtual memory. */
389 +/* Reverse the order of the ARGC pointers to char in ARGV. */
390 +static void
391 +reverse (int argc, char **argv) 
392 +{
393 +  for (; argc > 1; argc -= 2, argv++) 
394 +    {
395 +      char *tmp = argv[0];
396 +      argv[0] = argv[argc - 1];
397 +      argv[argc - 1] = tmp;
398 +    }
399 +}
400 +
401 +/* Pushes the SIZE bytes in BUF onto the stack in KPAGE, whose
402 +   page-relative stack pointer is *OFS, and then adjusts *OFS
403 +   appropriately.  The bytes pushed are rounded to a 32-bit
404 +   boundary.
405 +
406 +   If successful, returns a pointer to the newly pushed object.
407 +   On failure, returns a null pointer. */
408 +static void *
409 +push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size) 
410 +{
411 +  size_t padsize = ROUND_UP (size, sizeof (uint32_t));
412 +  if (*ofs < padsize)
413 +    return NULL;
414 +
415 +  *ofs -= padsize;
416 +  memcpy (kpage + *ofs + (padsize - size), buf, size);
417 +  return kpage + *ofs + (padsize - size);
418 +}
419 +
420 +/* Sets up command line arguments in KPAGE, which will be mapped
421 +   to UPAGE in user space.  The command line arguments are taken
422 +   from CMD_LINE, separated by spaces.  Sets *ESP to the initial
423 +   stack pointer for the process. */
424 +static bool
425 +init_cmd_line (uint8_t *kpage, uint8_t *upage, const char *cmd_line,
426 +               void **esp) 
427 +{
428 +  size_t ofs = PGSIZE;
429 +  char *const null = NULL;
430 +  char *cmd_line_copy;
431 +  char *karg, *saveptr;
432 +  int argc;
433 +  char **argv;
434 +
435 +  /* Push command line string. */
436 +  cmd_line_copy = push (kpage, &ofs, cmd_line, strlen (cmd_line) + 1);
437 +  if (cmd_line_copy == NULL)
438 +    return false;
439 +
440 +  if (push (kpage, &ofs, &null, sizeof null) == NULL)
441 +    return false;
442 +
443 +  /* Parse command line into arguments
444 +     and push them in reverse order. */
445 +  argc = 0;
446 +  for (karg = strtok_r (cmd_line_copy, " ", &saveptr); karg != NULL;
447 +       karg = strtok_r (NULL, " ", &saveptr))
448 +    {
449 +      void *uarg = upage + (karg - (char *) kpage);
450 +      if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
451 +        return false;
452 +      argc++;
453 +    }
454 +
455 +  /* Reverse the order of the command line arguments. */
456 +  argv = (char **) (upage + ofs);
457 +  reverse (argc, (char **) (kpage + ofs));
458 +
459 +  /* Push argv, argc, "return address". */
460 +  if (push (kpage, &ofs, &argv, sizeof argv) == NULL
461 +      || push (kpage, &ofs, &argc, sizeof argc) == NULL
462 +      || push (kpage, &ofs, &null, sizeof null) == NULL)
463 +    return false;
464 +
465 +  /* Set initial stack pointer. */
466 +  *esp = upage + ofs;
467 +  return true;
468 +}
469 +
470 +/* Create a minimal stack for T by mapping a page at the
471 +   top of user virtual memory.  Fills in the page using CMD_LINE
472 +   and sets *ESP to the stack pointer. */
473  static bool
474 -setup_stack (void **esp) 
475 +setup_stack (const char *cmd_line, void **esp) 
476  {
477    uint8_t *kpage;
478    bool success = false;
479 @@ -404,9 +587,9 @@ setup_stack (void **esp) 
480    kpage = palloc_get_page (PAL_USER | PAL_ZERO);
481    if (kpage != NULL) 
482      {
483 -      success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true);
484 -      if (success)
485 -        *esp = PHYS_BASE;
486 +      uint8_t *upage = ((uint8_t *) PHYS_BASE) - PGSIZE;
487 +      if (install_page (upage, kpage, true))
488 +        success = init_cmd_line (kpage, upage, cmd_line, esp);
489        else
490          palloc_free_page (kpage);
491      }
492 Index: src/userprog/syscall.c
493 diff -u src/userprog/syscall.c~ src/userprog/syscall.c
494 --- src/userprog/syscall.c~
495 +++ src/userprog/syscall.c
496 @@ -1,20 +1,483 @@
497  #include "userprog/syscall.h"
498  #include <stdio.h>
499 +#include <string.h>
500  #include <syscall-nr.h>
501 +#include "userprog/process.h"
502 +#include "userprog/pagedir.h"
503 +#include "devices/input.h"
504 +#include "filesys/filesys.h"
505 +#include "filesys/file.h"
506 +#include "threads/init.h"
507  #include "threads/interrupt.h"
508 +#include "threads/malloc.h"
509 +#include "threads/palloc.h"
510  #include "threads/thread.h"
511 +#include "threads/vaddr.h"
512 -
513
514
515 +static int sys_halt (void);
516 +static int sys_exit (int status);
517 +static int sys_exec (const char *ufile);
518 +static int sys_wait (tid_t);
519 +static int sys_create (const char *ufile, unsigned initial_size);
520 +static int sys_remove (const char *ufile);
521 +static int sys_open (const char *ufile);
522 +static int sys_filesize (int handle);
523 +static int sys_read (int handle, void *udst_, unsigned size);
524 +static int sys_write (int handle, void *usrc_, unsigned size);
525 +static int sys_seek (int handle, unsigned position);
526 +static int sys_tell (int handle);
527 +static int sys_close (int handle);
528
529  static void syscall_handler (struct intr_frame *);
530 -
531 +static void copy_in (void *, const void *, size_t);
532
533 +/* Serializes file system operations. */
534 +static struct lock fs_lock;
535
536  void
537  syscall_init (void) 
538  {
539    intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall");
540 +  lock_init (&fs_lock);
541  }
542
543 +/* System call handler. */
544 +static void
545 +syscall_handler (struct intr_frame *f) 
546 +{
547 +  typedef int syscall_function (int, int, int);
548 +
549 +  /* A system call. */
550 +  struct syscall 
551 +    {
552 +      size_t arg_cnt;           /* Number of arguments. */
553 +      syscall_function *func;   /* Implementation. */
554 +    };
555 +
556 +  /* Table of system calls. */
557 +  static const struct syscall syscall_table[] =
558 +    {
559 +      {0, (syscall_function *) sys_halt},
560 +      {1, (syscall_function *) sys_exit},
561 +      {1, (syscall_function *) sys_exec},
562 +      {1, (syscall_function *) sys_wait},
563 +      {2, (syscall_function *) sys_create},
564 +      {1, (syscall_function *) sys_remove},
565 +      {1, (syscall_function *) sys_open},
566 +      {1, (syscall_function *) sys_filesize},
567 +      {3, (syscall_function *) sys_read},
568 +      {3, (syscall_function *) sys_write},
569 +      {2, (syscall_function *) sys_seek},
570 +      {1, (syscall_function *) sys_tell},
571 +      {1, (syscall_function *) sys_close},
572 +    };
573 +
574 +  const struct syscall *sc;
575 +  unsigned call_nr;
576 +  int args[3];
577 +
578 +  /* Get the system call. */
579 +  copy_in (&call_nr, f->esp, sizeof call_nr);
580 +  if (call_nr >= sizeof syscall_table / sizeof *syscall_table)
581 +    thread_exit ();
582 +  sc = syscall_table + call_nr;
583  
584 +  /* Get the system call arguments. */
585 +  ASSERT (sc->arg_cnt <= sizeof args / sizeof *args);
586 +  memset (args, 0, sizeof args);
587 +  copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * sc->arg_cnt);
588 +
589 +  /* Execute the system call,
590 +     and set the return value. */
591 +  f->eax = sc->func (args[0], args[1], args[2]);
592 +}
593
594 +/* Returns true if UADDR is a valid, mapped user address,
595 +   false otherwise. */
596 +static bool
597 +verify_user (const void *uaddr) 
598 +{
599 +  return (uaddr < PHYS_BASE
600 +          && pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL);
601 +}
602
603 +/* Copies a byte from user address USRC to kernel address DST.
604 +   USRC must be below PHYS_BASE.
605 +   Returns true if successful, false if a segfault occurred. */
606 +static inline bool
607 +get_user (uint8_t *dst, const uint8_t *usrc)
608 +{
609 +  int eax;
610 +  asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
611 +       : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
612 +  return eax != 0;
613 +}
614
615 +/* Writes BYTE to user address UDST.
616 +   UDST must be below PHYS_BASE.
617 +   Returns true if successful, false if a segfault occurred. */
618 +static inline bool
619 +put_user (uint8_t *udst, uint8_t byte)
620 +{
621 +  int eax;
622 +  asm ("movl $1f, %%eax; movb %b2, %0; 1:"
623 +       : "=m" (*udst), "=&a" (eax) : "r" (byte));
624 +  return eax != 0;
625 +}
626
627 +/* Copies SIZE bytes from user address USRC to kernel address
628 +   DST.
629 +   Call thread_exit() if any of the user accesses are invalid. */
630  static void
631 -syscall_handler (struct intr_frame *f UNUSED) 
632 +copy_in (void *dst_, const void *usrc_, size_t size) 
633 +{
634 +  uint8_t *dst = dst_;
635 +  const uint8_t *usrc = usrc_;
636
637 +  for (; size > 0; size--, dst++, usrc++) 
638 +    if (usrc >= (uint8_t *) PHYS_BASE || !get_user (dst, usrc)) 
639 +      thread_exit ();
640 +}
641
642 +/* Creates a copy of user string US in kernel memory
643 +   and returns it as a page that must be freed with
644 +   palloc_free_page().
645 +   Truncates the string at PGSIZE bytes in size.
646 +   Call thread_exit() if any of the user accesses are invalid. */
647 +static char *
648 +copy_in_string (const char *us) 
649 +{
650 +  char *ks;
651 +  size_t length;
652
653 +  ks = palloc_get_page (0);
654 +  if (ks == NULL) 
655 +    thread_exit ();
656
657 +  for (length = 0; length < PGSIZE; length++)
658 +    {
659 +      if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++)) 
660 +        thread_exit (); 
661 +       
662 +      if (ks[length] == '\0')
663 +        return ks;
664 +    }
665 +  ks[PGSIZE - 1] = '\0';
666 +  return ks;
667 +}
668
669 +/* Halt system call. */
670 +static int
671 +sys_halt (void)
672 +{
673 +  power_off ();
674 +}
675
676 +/* Exit system call. */
677 +static int
678 +sys_exit (int exit_code) 
679 +{
680 +  thread_current ()->wait_status->exit_code = exit_code;
681 +  thread_exit ();
682 +  NOT_REACHED ();
683 +}
684
685 +/* Exec system call. */
686 +static int
687 +sys_exec (const char *ufile) 
688 +{
689 +  tid_t tid;
690 +  char *kfile = copy_in_string (ufile);
691
692 +  lock_acquire (&fs_lock);
693 +  tid = process_execute (kfile);
694 +  lock_release (&fs_lock);
695
696 +  palloc_free_page (kfile);
697
698 +  return tid;
699 +}
700
701 +/* Wait system call. */
702 +static int
703 +sys_wait (tid_t child) 
704 +{
705 +  return process_wait (child);
706 +}
707
708 +/* Create system call. */
709 +static int
710 +sys_create (const char *ufile, unsigned initial_size) 
711 +{
712 +  char *kfile = copy_in_string (ufile);
713 +  bool ok;
714 +   
715 +  lock_acquire (&fs_lock);
716 +  ok = filesys_create (kfile, initial_size);
717 +  lock_release (&fs_lock);
718
719 +  palloc_free_page (kfile);
720
721 +  return ok;
722 +}
723
724 +/* Remove system call. */
725 +static int
726 +sys_remove (const char *ufile) 
727  {
728 -  printf ("system call!\n");
729 +  char *kfile = copy_in_string (ufile);
730 +  bool ok;
731 +   
732 +  lock_acquire (&fs_lock);
733 +  ok = filesys_remove (kfile);
734 +  lock_release (&fs_lock);
735
736 +  palloc_free_page (kfile);
737
738 +  return ok;
739 +}
740
741 +/* A file descriptor, for binding a file handle to a file. */
742 +struct file_descriptor
743 +  {
744 +    struct list_elem elem;      /* List element. */
745 +    struct file *file;          /* File. */
746 +    int handle;                 /* File handle. */
747 +  };
748
749 +/* Open system call. */
750 +static int
751 +sys_open (const char *ufile) 
752 +{
753 +  char *kfile = copy_in_string (ufile);
754 +  struct file_descriptor *fd;
755 +  int handle = -1;
756
757 +  fd = malloc (sizeof *fd);
758 +  if (fd != NULL)
759 +    {
760 +      lock_acquire (&fs_lock);
761 +      fd->file = filesys_open (kfile);
762 +      if (fd->file != NULL)
763 +        {
764 +          struct thread *cur = thread_current ();
765 +          handle = fd->handle = cur->next_handle++;
766 +          list_push_front (&cur->fds, &fd->elem);
767 +        }
768 +      else 
769 +        free (fd);
770 +      lock_release (&fs_lock);
771 +    }
772 +  
773 +  palloc_free_page (kfile);
774 +  return handle;
775 +}
776
777 +/* Returns the file descriptor associated with the given handle.
778 +   Terminates the process if HANDLE is not associated with an
779 +   open file. */
780 +static struct file_descriptor *
781 +lookup_fd (int handle) 
782 +{
783 +  struct thread *cur = thread_current ();
784 +  struct list_elem *e;
785 +   
786 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
787 +       e = list_next (e))
788 +    {
789 +      struct file_descriptor *fd;
790 +      fd = list_entry (e, struct file_descriptor, elem);
791 +      if (fd->handle == handle)
792 +        return fd;
793 +    }
794
795    thread_exit ();
796  }
797
798 +/* Filesize system call. */
799 +static int
800 +sys_filesize (int handle) 
801 +{
802 +  struct file_descriptor *fd = lookup_fd (handle);
803 +  int size;
804
805 +  lock_acquire (&fs_lock);
806 +  size = file_length (fd->file);
807 +  lock_release (&fs_lock);
808
809 +  return size;
810 +}
811
812 +/* Read system call. */
813 +static int
814 +sys_read (int handle, void *udst_, unsigned size) 
815 +{
816 +  uint8_t *udst = udst_;
817 +  struct file_descriptor *fd;
818 +  int bytes_read = 0;
819 +
820 +  /* Handle keyboard reads. */
821 +  if (handle == STDIN_FILENO) 
822 +    {
823 +      for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
824 +        if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, input_getc ()))
825 +          thread_exit ();
826 +      return bytes_read;
827 +    }
828 +
829 +  /* Handle all other reads. */
830 +  fd = lookup_fd (handle);
831 +  lock_acquire (&fs_lock);
832 +  while (size > 0) 
833 +    {
834 +      /* How much to read into this page? */
835 +      size_t page_left = PGSIZE - pg_ofs (udst);
836 +      size_t read_amt = size < page_left ? size : page_left;
837 +      off_t retval;
838 +
839 +      /* Check that touching this page is okay. */
840 +      if (!verify_user (udst)) 
841 +        {
842 +          lock_release (&fs_lock);
843 +          thread_exit ();
844 +        }
845 +
846 +      /* Read from file into page. */
847 +      retval = file_read (fd->file, udst, read_amt);
848 +      if (retval < 0)
849 +        {
850 +          if (bytes_read == 0)
851 +            bytes_read = -1; 
852 +          break;
853 +        }
854 +      bytes_read += retval;
855 +
856 +      /* If it was a short read we're done. */
857 +      if (retval != (off_t) read_amt)
858 +        break;
859 +
860 +      /* Advance. */
861 +      udst += retval;
862 +      size -= retval;
863 +    }
864 +  lock_release (&fs_lock);
865 +   
866 +  return bytes_read;
867 +}
868
869 +/* Write system call. */
870 +static int
871 +sys_write (int handle, void *usrc_, unsigned size) 
872 +{
873 +  uint8_t *usrc = usrc_;
874 +  struct file_descriptor *fd = NULL;
875 +  int bytes_written = 0;
876 +
877 +  /* Lookup up file descriptor. */
878 +  if (handle != STDOUT_FILENO)
879 +    fd = lookup_fd (handle);
880 +
881 +  lock_acquire (&fs_lock);
882 +  while (size > 0) 
883 +    {
884 +      /* How much bytes to write to this page? */
885 +      size_t page_left = PGSIZE - pg_ofs (usrc);
886 +      size_t write_amt = size < page_left ? size : page_left;
887 +      off_t retval;
888 +
889 +      /* Check that we can touch this user page. */
890 +      if (!verify_user (usrc)) 
891 +        {
892 +          lock_release (&fs_lock);
893 +          thread_exit ();
894 +        }
895 +
896 +      /* Do the write. */
897 +      if (handle == STDOUT_FILENO)
898 +        {
899 +          putbuf (usrc, write_amt);
900 +          retval = write_amt;
901 +        }
902 +      else
903 +        retval = file_write (fd->file, usrc, write_amt);
904 +      if (retval < 0) 
905 +        {
906 +          if (bytes_written == 0)
907 +            bytes_written = -1;
908 +          break;
909 +        }
910 +      bytes_written += retval;
911 +
912 +      /* If it was a short write we're done. */
913 +      if (retval != (off_t) write_amt)
914 +        break;
915 +
916 +      /* Advance. */
917 +      usrc += retval;
918 +      size -= retval;
919 +    }
920 +  lock_release (&fs_lock);
921
922 +  return bytes_written;
923 +}
924
925 +/* Seek system call. */
926 +static int
927 +sys_seek (int handle, unsigned position) 
928 +{
929 +  struct file_descriptor *fd = lookup_fd (handle);
930 +   
931 +  lock_acquire (&fs_lock);
932 +  if ((off_t) position >= 0)
933 +    file_seek (fd->file, position);
934 +  lock_release (&fs_lock);
935
936 +  return 0;
937 +}
938
939 +/* Tell system call. */
940 +static int
941 +sys_tell (int handle) 
942 +{
943 +  struct file_descriptor *fd = lookup_fd (handle);
944 +  unsigned position;
945 +   
946 +  lock_acquire (&fs_lock);
947 +  position = file_tell (fd->file);
948 +  lock_release (&fs_lock);
949
950 +  return position;
951 +}
952
953 +/* Close system call. */
954 +static int
955 +sys_close (int handle) 
956 +{
957 +  struct file_descriptor *fd = lookup_fd (handle);
958 +  lock_acquire (&fs_lock);
959 +  file_close (fd->file);
960 +  lock_release (&fs_lock);
961 +  list_remove (&fd->elem);
962 +  free (fd);
963 +  return 0;
964 +}
965
966 +/* On thread exit, close all open files. */
967 +void
968 +syscall_exit (void) 
969 +{
970 +  struct thread *cur = thread_current ();
971 +  struct list_elem *e, *next;
972 +   
973 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
974 +    {
975 +      struct file_descriptor *fd;
976 +      fd = list_entry (e, struct file_descriptor, elem);
977 +      next = list_next (e);
978 +      lock_acquire (&fs_lock);
979 +      file_close (fd->file);
980 +      lock_release (&fs_lock);
981 +      free (fd);
982 +    }
983 +}
984 Index: src/userprog/syscall.h
985 diff -u src/userprog/syscall.h~ src/userprog/syscall.h
986 --- src/userprog/syscall.h~
987 +++ src/userprog/syscall.h
988 @@ -2,5 +2,6 @@
989  #define USERPROG_SYSCALL_H
990  
991  void syscall_init (void);
992 +void syscall_exit (void);
993  
994  #endif /* userprog/syscall.h */