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