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