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
5 #include "threads/synch.h"
7 #include "userprog/process.h"
8 +#include "userprog/syscall.h"
11 /* Random value for struct thread's `magic' member.
12 @@ -243,16 +244,19 @@ thread_tid (void)
16 + struct thread *t = thread_current ();
18 ASSERT (!intr_context ());
26 /* Just set our status to dying and schedule another process.
27 We will be destroyed during the call to schedule_tail(). */
29 - thread_current ()->status = THREAD_DYING;
30 + t->status = THREAD_DYING;
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);
40 + t->wait_status = NULL;
41 + list_init (&t->fds);
43 t->magic = THREAD_MAGIC;
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
53 +#include "threads/synch.h"
55 /* States in a thread's life cycle. */
57 @@ -89,6 +90,11 @@ struct thread
58 uint8_t *stack; /* Saved stack pointer. */
59 int priority; /* Priority. */
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. */
66 /* Shared between thread.c and synch.c. */
67 struct list_elem elem; /* List element. */
69 @@ -97,10 +103,29 @@ struct thread
70 uint32_t *pagedir; /* Page directory. */
73 + /* Owned by syscall.c. */
74 + struct list fds; /* List of file descriptors. */
75 + int next_handle; /* Next handle value. */
77 /* Owned by thread.c. */
78 unsigned magic; /* Detects stack overflow. */
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. */
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. */
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;
106 + /* Handle bad dereferences from system call implementations. */
109 + f->eip = (void (*) (void)) f->eax;
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
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"
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);
132 +/* Data structure shared between process_execute() in the
133 + invoking thread and execute_thread() in the newly invoked
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? */
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
147 process_execute (const char *filename)
150 + struct exec_info exec;
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)
158 - strlcpy (fn_copy, filename, PGSIZE);
159 + /* Initialize exec_info. */
160 + exec.filename = filename;
161 + sema_init (&exec.load_done, 0, "load done");
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)
170 + sema_down (&exec.load_done);
172 + list_push_back (&thread_current ()->children, &exec.wait_status->elem);
180 /* A thread function that loads a user process and starts it
183 -execute_thread (void *filename_)
184 +execute_thread (void *exec_)
186 - char *filename = filename_;
187 + struct exec_info *exec = exec_;
188 struct intr_frame if_;
191 @@ -57,10 +73,28 @@ execute_thread (void *filename_)
192 if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
194 if_.eflags = FLAG_IF | FLAG_MBS;
195 - success = load (filename, &if_.eip, &if_.esp);
196 + success = load (exec->filename, &if_.eip, &if_.esp);
198 + /* Allocate wait_status. */
201 + exec->wait_status = thread_current ()->wait_status
202 + = malloc (sizeof *exec->wait_status);
203 + success = exec->wait_status != NULL;
206 - /* If load failed, quit. */
207 - palloc_free_page (filename);
208 + /* Initialize wait_status. */
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");
217 + /* Notify parent thread and clean up. */
218 + exec->success = success;
219 + sema_up (&exec->load_done);
223 @@ -74,19 +108,48 @@ execute_thread (void *filename_)
227 +/* Releases one reference to CS and, if it is now unreferenced,
230 +release_child (struct wait_status *cs)
234 + lock_acquire (&cs->lock);
235 + new_ref_cnt = --cs->ref_cnt;
236 + lock_release (&cs->lock);
238 + if (new_ref_cnt == 0)
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.
249 - This function will be implemented in problem 2-2. For now, it
251 + immediately, without waiting. */
253 -process_wait (tid_t child_tid UNUSED)
254 +process_wait (tid_t child_tid)
256 + struct thread *cur = thread_current ();
257 + struct list_elem *e;
259 + for (e = list_begin (&cur->children); e != list_end (&cur->children);
262 + struct wait_status *cs = list_entry (e, struct wait_status, elem);
263 + if (cs->tid == child_tid)
267 + sema_down (&cs->dead);
268 + exit_code = cs->exit_code;
269 + release_child (cs);
276 /* Free the current process's resources. */
277 @@ -93,8 +157,29 @@ void
280 struct thread *cur = thread_current ();
281 + struct list_elem *e, *next;
284 + printf ("%s: exit(%d)\n", cur->name, cur->exit_code);
286 + /* Notify parent that we're dead. */
287 + if (cur->wait_status != NULL)
289 + struct wait_status *cs = cur->wait_status;
290 + cs->exit_code = cur->exit_code;
291 + sema_up (&cs->dead);
292 + release_child (cs);
295 + /* Free entries of children list. */
296 + for (e = list_begin (&cur->children); e != list_end (&cur->children);
299 + struct wait_status *cs = list_entry (e, struct wait_status, elem);
300 + next = list_remove (e);
301 + release_child (cs);
304 /* Destroy the current process's page directory and switch back
305 to the kernel-only page directory. */
307 @@ -192,7 +277,7 @@ struct Elf32_Phdr
308 #define PF_R 4 /* Readable. */
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);
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. */
320 -load (const char *filename, void (**eip) (void), void **esp)
321 +load (const char *cmd_line, void (**eip) (void), void **esp)
323 struct thread *t = thread_current ();
324 + char filename[NAME_MAX + 2];
325 struct Elf32_Ehdr ehdr;
326 struct file *file = NULL;
328 bool success = false;
332 /* Allocate and activate page directory. */
333 @@ -223,6 +310,14 @@ load (const char *filename, void (**eip)
334 LOAD_ERROR (("page directory allocation failed"));
337 + /* Extract filename from command line. */
338 + while (*cmd_line == ' ')
340 + strlcpy (filename, cmd_line, sizeof filename);
341 + cp = strchr (filename, ' ');
345 /* Open executable file. */
346 file = filesys_open (filename);
348 @@ -283,7 +378,7 @@ load (const char *filename, void (**eip)
352 - if (!setup_stack (esp))
353 + if (!setup_stack (cmd_line, esp))
357 @@ -392,10 +487,92 @@ load_segment (struct file *file, const s
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. */
365 +reverse (int argc, char **argv)
367 + for (; argc > 1; argc -= 2, argv++)
369 + char *tmp = argv[0];
370 + argv[0] = argv[argc - 1];
371 + argv[argc - 1] = tmp;
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
380 + If successful, returns a pointer to the newly pushed object.
381 + On failure, returns a null pointer. */
383 +push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size)
385 + size_t padsize = ROUND_UP (size, sizeof (uint32_t));
386 + if (*ofs < padsize)
390 + memcpy (kpage + *ofs + (padsize - size), buf, size);
391 + return kpage + *ofs + (padsize - size);
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. */
399 +init_cmd_line (uint8_t *kpage, uint8_t *upage, const char *cmd_line,
402 + size_t ofs = PGSIZE;
403 + char *const null = NULL;
404 + char *cmd_line_copy;
405 + char *karg, *saveptr;
409 + /* Push command line string. */
410 + cmd_line_copy = push (kpage, &ofs, cmd_line, strlen (cmd_line) + 1);
411 + if (cmd_line_copy == NULL)
414 + if (push (kpage, &ofs, &null, sizeof null) == NULL)
417 + /* Parse command line into arguments
418 + and push them in reverse order. */
420 + for (karg = strtok_r (cmd_line_copy, " ", &saveptr); karg != NULL;
421 + karg = strtok_r (NULL, " ", &saveptr))
423 + char *uarg = upage + (karg - (char *) kpage);
424 + if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
429 + /* Reverse the order of the command line arguments. */
430 + argv = (char **) (upage + ofs);
431 + reverse (argc, (char **) (kpage + ofs));
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)
439 + /* Set initial stack pointer. */
440 + *esp = upage + ofs;
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. */
448 -setup_stack (void **esp)
449 +setup_stack (const char *cmd_line, void **esp)
452 bool success = false;
453 @@ -403,9 +580,9 @@ setup_stack (void **esp)
454 kpage = palloc_get_page (PAL_USER | PAL_ZERO);
457 - success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
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);
464 palloc_free_page (kpage);
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
470 #include "userprog/syscall.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"
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);
502 static void syscall_handler (struct intr_frame *);
504 +static void copy_in (void *, const void *, size_t);
506 +static struct lock fs_lock;
511 intr_register (0x30, 3, INTR_ON, syscall_handler, "syscall");
512 + lock_init (&fs_lock, "fs");
515 +/* System call handler. */
517 +syscall_handler (struct intr_frame *f)
519 + typedef int syscall_function (int, int, int);
521 + /* A system call. */
524 + size_t arg_cnt; /* Number of arguments. */
525 + syscall_function *func; /* Implementation. */
528 + /* Table of system calls. */
529 + static const struct syscall syscall_table[] =
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},
546 + const struct syscall *sc;
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)
554 + sc = syscall_table + call_nr;
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);
561 + /* Execute the system call,
562 + and set the return value. */
563 + f->eax = sc->func (args[0], args[1], args[2]);
566 +/* Returns true if UADDR is a valid, mapped user address,
567 + false otherwise. */
569 +verify_user (const void *uaddr)
571 + return pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL;
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. */
578 +get_user (uint8_t *dst, const uint8_t *usrc)
581 + asm ("mov %%eax, offset 1f; mov %%al, %2; mov %0, %%al; 1:"
582 + : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
586 +/* Writes BYTE to user address UDST.
587 + UDST must be below PHYS_BASE.
588 + Returns true if successful, false if a segfault occurred. */
590 +put_user (uint8_t *udst, uint8_t byte)
593 + asm ("mov %%eax, offset 1f; mov %0, %b2; 1:"
594 + : "=m" (*udst), "=&a" (eax) : "r" (byte));
598 +/* Copies SIZE bytes from user address USRC to kernel address
600 + Call thread_exit() if any of the user accesses are invalid. */
602 -syscall_handler (struct intr_frame *f UNUSED)
603 +copy_in (void *dst_, const void *usrc_, size_t size)
605 + uint8_t *dst = dst_;
606 + const uint8_t *usrc = usrc_;
608 + for (; size > 0; size--, dst++, usrc++)
609 + if (usrc >= (uint8_t *) PHYS_BASE || !get_user (dst, usrc))
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. */
619 +copy_in_string (const char *us)
624 + ks = palloc_get_page (0);
628 + for (length = 0; length < PGSIZE; length++)
630 + if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++))
633 + if (ks[length] == '\0')
636 + ks[PGSIZE - 1] = '\0';
640 +/* Halt system call. */
647 +/* Exit system call. */
649 +sys_exit (int exit_code)
651 + thread_current ()->exit_code = exit_code;
656 +/* Exec system call. */
658 +sys_exec (const char *ufile)
661 + char *kfile = copy_in_string (ufile);
663 + lock_acquire (&fs_lock);
664 + tid = process_execute (kfile);
665 + lock_release (&fs_lock);
667 + palloc_free_page (kfile);
672 +/* Wait system call. */
674 +sys_wait (tid_t child)
676 + return process_wait (child);
679 +/* Create system call. */
681 +sys_create (const char *ufile, unsigned initial_size)
683 + char *kfile = copy_in_string (ufile);
686 + lock_acquire (&fs_lock);
687 + ok = filesys_create (kfile, initial_size);
688 + lock_release (&fs_lock);
690 + palloc_free_page (kfile);
695 +/* Remove system call. */
697 +sys_remove (const char *ufile)
699 - printf ("system call!\n");
700 + char *kfile = copy_in_string (ufile);
703 + lock_acquire (&fs_lock);
704 + ok = filesys_remove (kfile);
705 + lock_release (&fs_lock);
707 + palloc_free_page (kfile);
712 +/* A file descriptor, for binding a file handle to a file. */
713 +struct file_descriptor
715 + struct list_elem elem; /* List element. */
716 + struct file *file; /* File. */
717 + int handle; /* File handle. */
720 +/* Open system call. */
722 +sys_open (const char *ufile)
724 + char *kfile = copy_in_string (ufile);
725 + struct file_descriptor *fd;
728 + fd = malloc (sizeof *fd);
731 + lock_acquire (&fs_lock);
732 + fd->file = filesys_open (kfile);
733 + if (fd->file != NULL)
735 + struct thread *cur = thread_current ();
736 + handle = fd->handle = cur->next_handle++;
737 + list_push_front (&cur->fds, &fd->elem);
741 + lock_release (&fs_lock);
744 + palloc_free_page (kfile);
748 +/* Returns the file descriptor associated with the given handle.
749 + Terminates the process if HANDLE is not associated with an
751 +static struct file_descriptor *
752 +lookup_fd (int handle)
754 + struct thread *cur = thread_current ();
755 + struct list_elem *e;
757 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
760 + struct file_descriptor *fd;
761 + fd = list_entry (e, struct file_descriptor, elem);
762 + if (fd->handle == handle)
769 +/* Filesize system call. */
771 +sys_filesize (int handle)
773 + struct file_descriptor *fd = lookup_fd (handle);
776 + lock_acquire (&fs_lock);
777 + size = file_length (fd->file);
778 + lock_release (&fs_lock);
783 +/* Read system call. */
785 +sys_read (int handle, void *udst_, unsigned size)
787 + uint8_t *udst = udst_;
788 + struct file_descriptor *fd;
789 + int bytes_read = 0;
791 + /* Handle keyboard reads. */
792 + if (handle == STDIN_FILENO)
794 + for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
795 + if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, kbd_getc ()))
800 + /* Handle all other reads. */
801 + fd = lookup_fd (handle);
802 + lock_acquire (&fs_lock);
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;
810 + /* Check that touching this page is okay. */
811 + if (!verify_user (udst))
813 + lock_release (&fs_lock);
817 + /* Read from file into page. */
818 + retval = file_read (fd->file, udst, read_amt);
821 + if (bytes_read == 0)
825 + bytes_read += retval;
827 + /* If it was a short read we're done. */
828 + if (retval != (off_t) read_amt)
835 + lock_release (&fs_lock);
840 +/* Write system call. */
842 +sys_write (int handle, void *usrc_, unsigned size)
844 + uint8_t *usrc = usrc_;
845 + struct file_descriptor *fd = NULL;
846 + int bytes_written = 0;
848 + /* Lookup up file descriptor. */
849 + if (handle != STDOUT_FILENO)
850 + fd = lookup_fd (handle);
852 + lock_acquire (&fs_lock);
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;
860 + /* Check that we can touch this user page. */
861 + if (!verify_user (usrc))
863 + lock_release (&fs_lock);
867 + /* Do the write. */
868 + if (handle == STDOUT_FILENO)
870 + putbuf (usrc, write_amt);
871 + retval = write_amt;
874 + retval = file_write (fd->file, usrc, write_amt);
877 + if (bytes_written == 0)
878 + bytes_written = -1;
881 + bytes_written += retval;
883 + /* If it was a short write we're done. */
884 + if (retval != (off_t) write_amt)
891 + lock_release (&fs_lock);
893 + return bytes_written;
896 +/* Seek system call. */
898 +sys_seek (int handle, unsigned position)
900 + struct file_descriptor *fd = lookup_fd (handle);
902 + lock_acquire (&fs_lock);
903 + file_seek (fd->file, position);
904 + lock_release (&fs_lock);
909 +/* Tell system call. */
911 +sys_tell (int handle)
913 + struct file_descriptor *fd = lookup_fd (handle);
916 + lock_acquire (&fs_lock);
917 + position = file_tell (fd->file);
918 + lock_release (&fs_lock);
923 +/* Close system call. */
925 +sys_close (int handle)
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);
936 +/* On thread exit, close all open files. */
940 + struct thread *cur = thread_current ();
941 + struct list_elem *e, *next;
943 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
945 + struct file_descriptor *fd;
946 + fd = list_entry (e, struct file_descriptor, elem);
947 + next = list_next (e);
948 + file_close (fd->file);
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
956 #define USERPROG_SYSCALL_H
958 void syscall_init (void);
959 +void syscall_exit (void);
961 #endif /* userprog/syscall.h */