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