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