Change -nv to -v, -ns to -s, for consistency.
[pintos-anon] / solutions / p2.patch
1 diff -urp pintos.orig/src/constants.h pintos/src/constants.h
2 --- pintos.orig/src/constants.h 2004-09-21 17:26:39.000000000 -0700
3 +++ pintos/src/constants.h      2004-09-22 00:34:01.000000000 -0700
4 @@ -8,4 +8,4 @@
5  /*#define MACRONAME 1 */
6  
7  /* Uncomment if if you've implemented thread_join(). */
8 -/*#define THREAD_JOIN_IMPLEMENTED 1*/
9 +#define THREAD_JOIN_IMPLEMENTED 1
10 Only in pintos/src: constants.h~
11 diff -urp pintos.orig/src/threads/synch.c pintos/src/threads/synch.c
12 --- pintos.orig/src/threads/synch.c     2004-09-19 21:29:53.000000000 -0700
13 +++ pintos/src/threads/synch.c  2004-09-22 00:30:05.000000000 -0700
14 @@ -330,3 +330,35 @@ cond_name (const struct condition *cond)
15  
16    return cond->name;
17  }
18 +\f
19 +void
20 +latch_init (struct latch *latch, const char *name) 
21 +{
22 +  latch->released = false;
23 +  lock_init (&latch->monitor_lock, name);
24 +  cond_init (&latch->rel_cond, name);
25 +}
26 +
27 +void
28 +latch_acquire (struct latch *latch) 
29 +{
30 +  lock_acquire (&latch->monitor_lock);
31 +  if (!latch->released) 
32 +    {
33 +      cond_wait (&latch->rel_cond, &latch->monitor_lock);
34 +      ASSERT (latch->released); 
35 +    }
36 +  lock_release (&latch->monitor_lock);
37 +}
38 +
39 +void
40 +latch_release (struct latch *latch) 
41 +{
42 +  lock_acquire (&latch->monitor_lock);
43 +  if (!latch->released)
44 +    {
45 +      latch->released = true;
46 +      cond_signal (&latch->rel_cond, &latch->monitor_lock);
47 +    }
48 +  lock_release (&latch->monitor_lock);
49 +}
50 diff -urp pintos.orig/src/threads/synch.h pintos/src/threads/synch.h
51 --- pintos.orig/src/threads/synch.h     2004-09-19 21:29:53.000000000 -0700
52 +++ pintos/src/threads/synch.h  2004-09-22 00:30:05.000000000 -0700
53 @@ -44,4 +44,16 @@ void cond_signal (struct condition *, st
54  void cond_broadcast (struct condition *, struct lock *);
55  const char *cond_name (const struct condition *);
56  
57 +/* Latch. */
58 +struct latch 
59 +  {
60 +    bool released;              /* Released yet? */
61 +    struct lock monitor_lock;   /* Monitor lock. */
62 +    struct condition rel_cond;  /* Signaled when released. */
63 +  };
64 +
65 +void latch_init (struct latch *, const char *);
66 +void latch_acquire (struct latch *);
67 +void latch_release (struct latch *);
68 +
69  #endif /* threads/synch.h */
70 diff -urp pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
71 --- pintos.orig/src/threads/thread.c    2004-09-21 22:42:17.000000000 -0700
72 +++ pintos/src/threads/thread.c 2004-09-22 00:32:39.000000000 -0700
73 @@ -13,6 +13,7 @@
74  #include "threads/synch.h"
75  #ifdef USERPROG
76  #include "userprog/process.h"
77 +#include "userprog/syscall.h"
78  #endif
79  
80  /* Random value for struct thread's `magic' member.
81 @@ -75,6 +76,7 @@ thread_init (void) 
82    init_thread (initial_thread, "main", PRI_DEFAULT);
83    initial_thread->status = THREAD_RUNNING;
84    initial_thread->tid = allocate_tid ();
85 +  sema_up (&initial_thread->can_die);
86  }
87  
88  /* Starts preemptive thread scheduling by enabling interrupts.
89 @@ -119,6 +121,7 @@ thread_create (const char *name, int pri
90    /* Initialize thread. */
91    init_thread (t, name, priority);
92    tid = t->tid = allocate_tid ();
93 +  list_push_back (&thread_current ()->children, &t->children_elem);
94  
95    /* Stack frame for kernel_thread(). */
96    kf = alloc_frame (t, sizeof *kf);
97 @@ -195,16 +198,36 @@ thread_tid (void) 
98  void
99  thread_exit (void) 
100  {
101 +  struct thread *t = thread_current ();
102 +  list_elem *e, *next;
103 +
104    ASSERT (!intr_context ());
105  
106  #ifdef USERPROG
107    process_exit ();
108  #endif
109 +  syscall_exit ();
110 +  
111 +  /* Notify our parent that we're dying. */
112 +  latch_release (&t->ready_to_die);
113 +
114 +  /* Notify our children that they can die. */
115 +  for (e = list_begin (&t->children); e != list_end (&t->children);
116 +       e = next) 
117 +    {
118 +      struct thread *child = list_entry (e, struct thread, children_elem);
119 +      next = list_next (e);
120 +      list_remove (e);
121 +      sema_up (&child->can_die); 
122 +    }
123 +
124 +  /* Wait until our parent is ready for us to die. */
125 +  sema_down (&t->can_die);
126  
127    /* Just set our status to dying and schedule another process.
128       We will be destroyed during the call to schedule_tail(). */
129    intr_disable ();
130 -  thread_current ()->status = THREAD_DYING;
131 +  t->status = THREAD_DYING;
132    schedule ();
133    NOT_REACHED ();
134  }
135 @@ -241,6 +264,26 @@ thread_block (void) 
136    thread_current ()->status = THREAD_BLOCKED;
137    schedule ();
138  }
139 +
140 +/* Waits for thread with tid CHILD_TID to die. */
141 +int
142 +thread_join (tid_t child_tid) 
143 +{
144 +  struct thread *cur = thread_current ();
145 +  list_elem *e;
146 +
147 +  for (e = list_begin (&cur->children); e != list_end (&cur->children); ) 
148 +    {
149 +      struct thread *child = list_entry (e, struct thread, children_elem);
150 +      e = list_next (e);
151 +      if (child->tid == child_tid) 
152 +        {
153 +          latch_acquire (&child->ready_to_die);
154 +          return child->ret_code; 
155 +        }
156 +    }
157 +  return -1;
158 +}
159  \f
160  /* Idle thread.  Executes when no other thread is ready to run. */
161  static void
162 @@ -306,6 +349,12 @@ init_thread (struct thread *t, const cha
163    strlcpy (t->name, name, sizeof t->name);
164    t->stack = (uint8_t *) t + PGSIZE;
165    t->priority = priority;
166 +  latch_init (&t->ready_to_die, "ready-to-die");
167 +  sema_init (&t->can_die, 0, "can-die");
168 +  list_init (&t->children);
169 +  t->ret_code = -1;
170 +  list_init (&t->fds);
171 +  t->next_handle = 2;
172    t->magic = THREAD_MAGIC;
173  }
174  
175 Only in pintos/src/threads: thread.c.orig
176 Only in pintos/src/threads: thread.c.rej
177 Only in pintos/src/threads: thread.c~
178 diff -urp pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
179 --- pintos.orig/src/threads/thread.h    2004-09-20 15:29:18.000000000 -0700
180 +++ pintos/src/threads/thread.h 2004-09-22 00:30:05.000000000 -0700
181 @@ -4,6 +4,7 @@
182  #include <debug.h>
183  #include <list.h>
184  #include <stdint.h>
185 +#include "threads/synch.h"
186  
187  /* States in a thread's life cycle. */
188  enum thread_status
189 @@ -89,12 +90,23 @@ struct thread
190      uint8_t *stack;                     /* Saved stack pointer. */
191      int priority;                       /* Priority. */
192  
193 +    /* Members for implementing thread_join(). */
194 +    struct latch ready_to_die;          /* Release when thread about to die. */
195 +    struct semaphore can_die;           /* Up when thread allowed to die. */
196 +    struct list children;               /* List of child threads. */
197 +    list_elem children_elem;            /* Element of `children' list. */
198 +    int ret_code;                       /* Return status. */
199 +
200      /* Shared between thread.c and synch.c. */
201      list_elem elem;                     /* List element. */
202  
203  #ifdef USERPROG
204      /* Owned by userprog/process.c. */
205      uint32_t *pagedir;                  /* Page directory. */
206 +
207 +    /* Owned by syscall.c. */
208 +    struct list fds;                    /* List of file descriptors. */
209 +    int next_handle;                    /* Next handle value. */
210  #endif
211  
212      /* Owned by thread.c */
213 @@ -117,7 +129,7 @@ void thread_yield (void);
214  void thread_block (void);
215  
216  /* This function will be implemented in problem 1-2. */
217 -void thread_join (tid_t);
218 +int thread_join (tid_t);
219  
220  /* These functions will be implemented in problem 1-3. */
221  void thread_set_priority (int);
222 Only in pintos/src/userprog: build
223 diff -urp pintos.orig/src/userprog/exception.c pintos/src/userprog/exception.c
224 --- pintos.orig/src/userprog/exception.c        2004-09-20 12:06:58.000000000 -0700
225 +++ pintos/src/userprog/exception.c     2004-09-22 00:30:05.000000000 -0700
226 @@ -134,6 +134,13 @@ page_fault (struct intr_frame *f) 
227    write = (f->error_code & PF_W) != 0;
228    user = (f->error_code & PF_U) != 0;
229  
230 +  if (!user) 
231 +    {
232 +      f->eip = (void (*) (void)) f->eax;
233 +      f->eax = 0;
234 +      return;
235 +    }
236 +
237    /* To implement virtual memory, delete the rest of the function
238       body, and replace it with code that brings in the page to
239       which fault_addr refers. */
240 diff -urp pintos.orig/src/userprog/pagedir.c pintos/src/userprog/pagedir.c
241 --- pintos.orig/src/userprog/pagedir.c  2004-09-21 22:42:17.000000000 -0700
242 +++ pintos/src/userprog/pagedir.c       2004-09-22 00:32:23.000000000 -0700
243 @@ -99,7 +99,7 @@ pagedir_set_page (uint32_t *pd, void *up
244    ASSERT (pg_ofs (upage) == 0);
245    ASSERT (pg_ofs (kpage) == 0);
246    ASSERT (upage < PHYS_BASE);
247 -  ASSERT (lookup_page (pd, upage, false) == NULL);
248 +  ASSERT (pagedir_get_page (pd, upage) == NULL);
249  
250    pte = lookup_page (pd, upage, true);
251    if (pte != NULL) 
252 Only in pintos/src/userprog: pagedir.c.orig
253 Only in pintos/src/userprog: pagedir.c.rej
254 Only in pintos/src/userprog: pagedir.c.rej~
255 Only in pintos/src/userprog: pagedir.c~
256 diff -urp pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
257 --- pintos.orig/src/userprog/process.c  2004-09-21 22:42:17.000000000 -0700
258 +++ pintos/src/userprog/process.c       2004-09-22 00:30:05.000000000 -0700
259 @@ -182,7 +182,7 @@ struct Elf32_Phdr
260  #define PF_R 4          /* Readable. */
261  
262  static bool load_segment (struct file *, const struct Elf32_Phdr *);
263 -static bool setup_stack (void **esp);
264 +static bool setup_stack (const char *cmdline, void **esp);
265  
266  /* Aborts loading an executable, with an error message. */
267  #define LOAD_ERROR(MSG)                                         \
268 @@ -198,13 +198,15 @@ static bool setup_stack (void **esp);
269     and its initial stack pointer into *ESP.
270     Returns true if successful, false otherwise. */
271  bool
272 -load (const char *filename, void (**eip) (void), void **esp) 
273 +load (const char *cmdline, void (**eip) (void), void **esp) 
274  {
275    struct thread *t = thread_current ();
276 +  char filename[NAME_MAX + 2];
277    struct Elf32_Ehdr ehdr;
278    struct file *file = NULL;
279    off_t file_ofs;
280    bool success = false;
281 +  char *cp;
282    int i;
283  
284    /* Allocate page directory. */
285 @@ -212,6 +214,14 @@ load (const char *filename, void (**eip)
286    if (t->pagedir == NULL)
287      LOAD_ERROR (("page directory allocation failed"));
288  
289 +  /* Extract filename from command line. */
290 +  while (*cmdline == ' ')
291 +    cmdline++;
292 +  strlcpy (filename, cmdline, sizeof filename);
293 +  cp = strchr (filename, ' ');
294 +  if (cp != NULL)
295 +    *cp = '\0';
296 +
297    /* Open executable file. */
298    file = filesys_open (filename);
299    if (file == NULL)
300 @@ -269,7 +279,7 @@ load (const char *filename, void (**eip)
301      }
302  
303    /* Set up stack. */
304 -  if (!setup_stack (esp))
305 +  if (!setup_stack (cmdline, esp))
306      goto done;
307  
308    /* Start address. */
309 @@ -371,10 +381,80 @@ load_segment (struct file *file, const s
310    return true;
311  }
312  
313 -/* Create a minimal stack by mapping a zeroed page at the top of
314 -   user virtual memory. */
315 +static void
316 +reverse (int argc, char **argv) 
317 +{
318 +  for (; argc > 1; argc -= 2, argv++) 
319 +    {
320 +      char *tmp = argv[0];
321 +      argv[0] = argv[argc - 1];
322 +      argv[argc - 1] = tmp;
323 +    }
324 +}
325 +
326 +static void *
327 +push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size) 
328 +{
329 +  size_t padsize = ROUND_UP (size, sizeof (uint32_t));
330 +  if (*ofs < padsize)
331 +    return NULL;
332 +
333 +  *ofs -= padsize;
334 +  memcpy (kpage + *ofs + (padsize - size), buf, size);
335 +  return kpage + *ofs + (padsize - size);
336 +}
337 +
338 +static bool
339 +init_cmdline (uint8_t *kpage, uint8_t *upage, const char *cmdline,
340 +              void **esp) 
341 +{
342 +  size_t ofs = PGSIZE;
343 +  char *const null = NULL;
344 +  char *cmdline_copy;
345 +  char *karg, *saveptr;
346 +  int argc;
347 +  char **argv;
348 +
349 +  /* Push command line string. */
350 +  cmdline_copy = push (kpage, &ofs, cmdline, strlen (cmdline) + 1);
351 +  if (cmdline_copy == NULL)
352 +    return false;
353 +
354 +  if (push (kpage, &ofs, &null, sizeof null) == NULL)
355 +    return false;
356 +
357 +  /* Parse command line into arguments
358 +     and push them in reverse order. */
359 +  argc = 0;
360 +  for (karg = strtok_r (cmdline_copy, " ", &saveptr); karg != NULL;
361 +       karg = strtok_r (NULL, " ", &saveptr))
362 +    {
363 +      char *uarg = upage + (karg - (char *) kpage);
364 +      if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
365 +        return false;
366 +      argc++;
367 +    }
368 +
369 +  /* Reverse the order of the command line arguments. */
370 +  argv = (char **) (upage + ofs);
371 +  reverse (argc, (char **) (kpage + ofs));
372 +
373 +  /* Push argv, argc, "return address". */
374 +  if (push (kpage, &ofs, &argv, sizeof argv) == NULL
375 +      || push (kpage, &ofs, &argc, sizeof argc) == NULL
376 +      || push (kpage, &ofs, &null, sizeof null) == NULL)
377 +    return false;
378 +
379 +  /* Set initial stack pointer. */
380 +  *esp = upage + ofs;
381 +  return true;
382 +}
383 +
384 +/* Create a minimal stack for T by mapping a page at the
385 +   top of user virtual memory.  Fills in the page using CMDLINE
386 +   and sets *ESP to the stack pointer. */
387  static bool
388 -setup_stack (void **esp) 
389 +setup_stack (const char *cmdline, void **esp) 
390  {
391    uint8_t *kpage;
392    bool success = false;
393 @@ -382,9 +462,9 @@ setup_stack (void **esp) 
394    kpage = palloc_get (PAL_USER | PAL_ZERO);
395    if (kpage != NULL) 
396      {
397 -      success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
398 -      if (success)
399 -        *esp = PHYS_BASE;
400 +      uint8_t *upage = ((uint8_t *) PHYS_BASE) - PGSIZE;
401 +      if (install_page (upage, kpage))
402 +        success = init_cmdline (kpage, upage, cmdline, esp);
403        else
404          palloc_free (kpage);
405      }
406 Only in pintos/src/userprog: process.c.orig
407 diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
408 --- pintos.orig/src/userprog/syscall.c  2004-09-05 22:19:19.000000000 -0700
409 +++ pintos/src/userprog/syscall.c       2004-09-22 00:30:05.000000000 -0700
410 @@ -1,20 +1,429 @@
411  #include "userprog/syscall.h"
412  #include <stdio.h>
413 +#include <string.h>
414  #include <syscall-nr.h>
415 +#include "userprog/process.h"
416 +#include "userprog/pagedir.h"
417 +#include "devices/kbd.h"
418 +#include "filesys/filesys.h"
419 +#include "filesys/file.h"
420 +#include "threads/init.h"
421  #include "threads/interrupt.h"
422 +#include "threads/malloc.h"
423 +#include "threads/mmu.h"
424 +#include "threads/palloc.h"
425  #include "threads/thread.h"
426  
427 +typedef int syscall_function (int, int, int);
428 +
429 +static int sys_halt (void);
430 +static int sys_exit (int status);
431 +static int sys_exec (const char *ufile);
432 +static int sys_join (tid_t);
433 +static int sys_create (const char *ufile, unsigned initial_size);
434 +static int sys_remove (const char *ufile);
435 +static int sys_open (const char *ufile);
436 +static int sys_filesize (int handle);
437 +static int sys_read (int handle, void *udst_, unsigned size);
438 +static int sys_write (int handle, void *usrc_, unsigned size);
439 +static int sys_seek (int handle, unsigned position);
440 +static int sys_tell (int handle);
441 +static int sys_close (int handle);
442 +
443 +struct syscall 
444 +  {
445 +    size_t arg_cnt;
446 +    syscall_function *func;
447 +  };
448 +
449 +struct syscall syscall_table[] = 
450 +  {
451 +    {0, (syscall_function *) sys_halt},
452 +    {1, (syscall_function *) sys_exit},
453 +    {1, (syscall_function *) sys_exec},
454 +    {1, (syscall_function *) sys_join},
455 +    {2, (syscall_function *) sys_create},
456 +    {1, (syscall_function *) sys_remove},
457 +    {1, (syscall_function *) sys_open},
458 +    {1, (syscall_function *) sys_filesize},
459 +    {3, (syscall_function *) sys_read},
460 +    {3, (syscall_function *) sys_write},
461 +    {2, (syscall_function *) sys_seek},
462 +    {1, (syscall_function *) sys_tell},
463 +    {1, (syscall_function *) sys_close},
464 +  };
465 +static const int syscall_cnt = sizeof syscall_table / sizeof *syscall_table;
466 +
467  static void syscall_handler (struct intr_frame *);
468 +static void copy_in (void *, const void *, size_t);
469 +
470 +static struct lock fs_lock;
471  
472  void
473  syscall_init (void) 
474  {
475    intr_register (0x30, 3, INTR_ON, syscall_handler, "syscall");
476 +  lock_init (&fs_lock, "fs");
477  }
478  
479  static void
480  syscall_handler (struct intr_frame *f) 
481  {
482 -  printf ("system call!\n");
483 +  struct syscall *s;
484 +  int call_nr;
485 +  int args[3];
486 +
487 +  copy_in (&call_nr, f->esp, sizeof call_nr);
488 +  if (call_nr < 0 || call_nr >= syscall_cnt)
489 +    {
490 +      printf ("bad syscall number %d\n", call_nr);
491 +      thread_exit ();
492 +    }
493 +
494 +  s = syscall_table + call_nr;
495 +  ASSERT (s->arg_cnt <= sizeof args / sizeof *args);
496 +  memset (args, 0, sizeof args);
497 +  copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * s->arg_cnt);
498 +  f->eax = s->func (args[0], args[1], args[2]);
499 +}
500 +
501 +static bool
502 +verify_user (const void *uaddr) 
503 +{
504 +  return pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL;
505 +}
506 +
507 +static inline bool get_user (uint8_t *dst, const uint8_t *usrc) {
508 +  int eax;
509 +  asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
510 +       : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
511 +  return eax != 0;
512 +}
513 +
514 +static inline bool put_user (uint8_t *udst, uint8_t byte) {
515 +  int eax;
516 +  asm ("movl $1f, %%eax; movb %b2, %0; 1:"
517 +       : "=m" (*udst), "=&a" (eax) : "r" (byte));
518 +  return eax != 0;
519 +}
520 +
521 +static void
522 +copy_in (void *dst_, const void *usrc_, size_t size) 
523 +{
524 +  uint8_t *dst = dst_;
525 +  const uint8_t *usrc = usrc_;
526 +
527 +  for (; size > 0; size--, dst++, usrc++) 
528 +    if (usrc >= (uint8_t *) PHYS_BASE || !get_user (dst, usrc)) 
529 +      thread_exit ();
530 +}
531 +
532 +static char *
533 +copy_in_string (const char *us) 
534 +{
535 +  char *ks;
536 +  size_t length;
537 +
538 +  ks = palloc_get (0);
539 +  if (ks == NULL) 
540 +    {
541 +      printf ("copy_in_string: out of memory\n");
542 +      thread_exit ();
543 +    }
544 +
545 +  for (length = 0; length < PGSIZE; length++)
546 +    {
547 +      if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++)) 
548 +        {
549 +          printf ("bad user reference (%p)\n", us + length);
550 +          thread_exit (); 
551 +        }
552 +      
553 +      if (ks[length] == '\0')
554 +        return ks;
555 +    }
556 +
557 +  printf ("copy_in_string: string too long\n");
558 +  palloc_free (ks);
559 +  thread_exit ();
560 +}
561 +
562 +static int
563 +sys_halt (void)
564 +{
565 +  power_off ();
566 +}
567 +
568 +static int
569 +sys_exit (int ret_code) 
570 +{
571 +  thread_current ()->ret_code = ret_code;
572 +  thread_exit ();
573 +  NOT_REACHED ();
574 +}
575 +
576 +static int
577 +sys_exec (const char *ufile) 
578 +{
579 +  tid_t tid;
580 +  char *kfile = copy_in_string (ufile);
581 +
582 +  lock_acquire (&fs_lock);
583 +  tid = process_execute (kfile);
584 +  lock_release (&fs_lock);
585 +
586 +  palloc_free (kfile);
587 +
588 +  return tid;
589 +}
590 +
591 +static int
592 +sys_join (tid_t child) 
593 +{
594 +  return thread_join (child);
595 +}
596 +
597 +static int
598 +sys_create (const char *ufile, unsigned initial_size) 
599 +{
600 +  char *kfile = copy_in_string (ufile);
601 +  bool ok;
602 +  
603 +  lock_acquire (&fs_lock);
604 +  ok = filesys_create (kfile, initial_size);
605 +  lock_release (&fs_lock);
606 +
607 +  palloc_free (kfile);
608 +
609 +  return ok;
610 +}
611 +
612 +static int
613 +sys_remove (const char *ufile) 
614 +{
615 +  char *kfile = copy_in_string (ufile);
616 +  bool ok;
617 +  
618 +  lock_acquire (&fs_lock);
619 +  ok = filesys_remove (kfile);
620 +  lock_release (&fs_lock);
621 +
622 +  palloc_free (kfile);
623 +
624 +  return ok;
625 +}
626 +
627 +struct fildes
628 +  {
629 +    list_elem elem;
630 +    struct file *file;
631 +    int handle;
632 +  };
633 +
634 +static int
635 +sys_open (const char *ufile) 
636 +{
637 +  char *kfile = copy_in_string (ufile);
638 +  struct fildes *fd;
639 +  int handle = -1;
640 +
641 +  fd = malloc (sizeof *fd);
642 +  if (fd == NULL)
643 +    goto exit;
644 +
645 +  lock_acquire (&fs_lock);
646 +  fd->file = filesys_open (kfile);
647 +  if (fd->file != NULL)
648 +    {
649 +      struct thread *cur = thread_current ();
650 +      handle = fd->handle = cur->next_handle++;
651 +      list_push_front (&cur->fds, &fd->elem);
652 +    }
653 +  else 
654 +    free (fd);
655 +  lock_release (&fs_lock);
656 +
657 + exit:
658 +  palloc_free (kfile);
659 +  return handle;
660 +}
661 +
662 +static struct fildes *
663 +lookup_fd (int handle) 
664 +{
665 +  struct thread *cur = thread_current ();
666 +  list_elem *e;
667 +  
668 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
669 +       e = list_next (e))
670 +    {
671 +      struct fildes *fd = list_entry (e, struct fildes, elem);
672 +      if (fd->handle == handle)
673 +        return fd;
674 +    }
675 +
676 +  printf ("no handle %d\n", handle);
677    thread_exit ();
678  }
679 +
680 +static int
681 +sys_filesize (int handle) 
682 +{
683 +  struct fildes *fd = lookup_fd (handle);
684 +  int size;
685 +
686 +  lock_acquire (&fs_lock);
687 +  size = file_length (fd->file);
688 +  lock_release (&fs_lock);
689 +
690 +  return size;
691 +}
692 +
693 +static int
694 +sys_read (int handle, void *udst_, unsigned size) 
695 +{
696 +  uint8_t *udst = udst_;
697 +  struct fildes *fd;
698 +  int bytes_read = 0;
699 +
700 +  if (handle == STDIN_FILENO) 
701 +    {
702 +      for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
703 +        if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, kbd_getc ()))
704 +          thread_exit ();
705 +      return bytes_read;
706 +    }
707 +
708 +  lock_acquire (&fs_lock);
709 +  fd = lookup_fd (handle);
710 +  while (size > 0) 
711 +    {
712 +      size_t page_left = PGSIZE - pg_ofs (udst);
713 +      size_t read_amt = size < page_left ? size : page_left;
714 +      off_t retval;
715 +
716 +      if (!verify_user (udst)) 
717 +        {
718 +          lock_release (&fs_lock);
719 +          thread_exit ();
720 +        }
721 +      
722 +      retval = file_read (fd->file, udst, read_amt);
723 +      if (retval < 0)
724 +        {
725 +          if (bytes_read == 0)
726 +            bytes_read = -1; 
727 +          break;
728 +        }
729 +
730 +      bytes_read += retval;
731 +      if (retval != (off_t) read_amt)
732 +        break;
733 +
734 +      udst += retval;
735 +      size -= retval;
736 +    }
737 +  lock_release (&fs_lock);
738 +  
739 +  return bytes_read;
740 +}
741 +
742 +static int
743 +sys_write (int handle, void *usrc_, unsigned size) 
744 +{
745 +  uint8_t *usrc = usrc_;
746 +  struct fildes *fd = NULL;
747 +  int bytes_written = 0;
748 +
749 +  lock_acquire (&fs_lock);
750 +  if (handle != STDOUT_FILENO)
751 +    fd = lookup_fd (handle);
752 +  while (size > 0) 
753 +    {
754 +      size_t page_left = PGSIZE - pg_ofs (usrc);
755 +      size_t write_amt = size < page_left ? size : page_left;
756 +      off_t retval;
757 +
758 +      if (!verify_user (usrc)) 
759 +        {
760 +          lock_release (&fs_lock);
761 +          thread_exit ();
762 +        }
763 +
764 +      if (handle == STDOUT_FILENO)
765 +        {
766 +          putbuf (usrc, write_amt);
767 +          retval = write_amt;
768 +        }
769 +      else
770 +        retval = file_write (fd->file, usrc, write_amt);
771 +      if (retval < 0) 
772 +        {
773 +          if (bytes_written == 0)
774 +            bytes_written = -1;
775 +          break;
776 +        }
777 +
778 +      bytes_written += retval;
779 +      if (retval != (off_t) write_amt)
780 +        break;
781 +
782 +      usrc += retval;
783 +      size -= retval;
784 +    }
785 +  lock_release (&fs_lock);
786 +
787 +  return bytes_written;
788 +}
789 +
790 +static int
791 +sys_seek (int handle, unsigned position) 
792 +{
793 +  struct fildes *fd = lookup_fd (handle);
794 +  
795 +  lock_acquire (&fs_lock);
796 +  file_seek (fd->file, position);
797 +  lock_release (&fs_lock);
798 +
799 +  return 0;
800 +}
801 +
802 +static int
803 +sys_tell (int handle) 
804 +{
805 +  struct fildes *fd = lookup_fd (handle);
806 +  unsigned position;
807 +  
808 +  lock_acquire (&fs_lock);
809 +  position = file_tell (fd->file);
810 +  lock_release (&fs_lock);
811 +
812 +  return position;
813 +}
814 +
815 +static int
816 +sys_close (int handle) 
817 +{
818 +  struct fildes *fd = lookup_fd (handle);
819 +  lock_acquire (&fs_lock);
820 +  file_close (fd->file);
821 +  lock_release (&fs_lock);
822 +  list_remove (&fd->elem);
823 +  free (fd);
824 +  return 0;
825 +}
826 +
827 +void
828 +syscall_exit (void) 
829 +{
830 +  struct thread *cur = thread_current ();
831 +  list_elem *e, *next;
832 +  
833 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
834 +    {
835 +      struct fildes *fd = list_entry (e, struct fildes, elem);
836 +      next = list_next (e);
837 +      file_close (fd->file);
838 +      free (fd);
839 +    }
840 +}
841 diff -urp pintos.orig/src/userprog/syscall.h pintos/src/userprog/syscall.h
842 --- pintos.orig/src/userprog/syscall.h  2004-09-05 22:38:45.000000000 -0700
843 +++ pintos/src/userprog/syscall.h       2004-09-22 00:30:05.000000000 -0700
844 @@ -2,5 +2,6 @@
845  #define USERPROG_SYSCALL_H
846  
847  void syscall_init (void);
848 +void syscall_exit (void);
849  
850  #endif /* userprog/syscall.h */