1 Index: src/threads/thread.c
2 diff -u src/threads/thread.c~ src/threads/thread.c
3 --- src/threads/thread.c~
4 +++ src/threads/thread.c
6 #include "threads/synch.h"
8 #include "userprog/process.h"
9 +#include "userprog/syscall.h"
12 /* Random value for struct thread's `magic' member.
13 @@ -251,16 +252,19 @@ thread_tid (void)
17 + struct thread *t = thread_current ();
19 ASSERT (!intr_context ());
27 /* Just set our status to dying and schedule another process.
28 We will be destroyed during the call to schedule_tail(). */
30 - thread_current ()->status = THREAD_DYING;
31 + t->status = THREAD_DYING;
35 @@ -400,6 +404,10 @@ init_thread (struct thread *t, const cha
36 strlcpy (t->name, name, sizeof t->name);
37 t->stack = (uint8_t *) t + PGSIZE;
38 t->priority = priority;
39 + list_init (&t->children);
40 + t->wait_status = NULL;
41 + list_init (&t->fds);
43 t->magic = THREAD_MAGIC;
46 Index: src/threads/thread.h
47 diff -u src/threads/thread.h~ src/threads/thread.h
48 --- src/threads/thread.h~
49 +++ src/threads/thread.h
54 +#include "threads/synch.h"
56 /* States in a thread's life cycle. */
58 @@ -89,6 +90,10 @@ struct thread
59 uint8_t *stack; /* Saved stack pointer. */
60 int priority; /* Priority. */
62 + /* Owned by process.c. */
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 @@ -96,11 +102,31 @@ struct thread
70 /* Owned by userprog/process.c. */
71 uint32_t *pagedir; /* Page directory. */
73 + struct file *bin_file; /* Executable. */
75 + /* Owned by syscall.c. */
76 + struct list fds; /* List of file descriptors. */
77 + int next_handle; /* Next handle value. */
79 /* Owned by thread.c. */
80 unsigned magic; /* Detects stack overflow. */
83 +/* Tracks the completion of a process.
84 + Reference held by both the parent, in its `children' list,
85 + and by the child, in its `wait_status' pointer. */
88 + struct list_elem elem; /* `children' list element. */
89 + struct lock lock; /* Protects ref_cnt. */
90 + int ref_cnt; /* 2=child and parent both alive,
91 + 1=either child or parent alive,
92 + 0=child and parent both dead. */
93 + tid_t tid; /* Child thread id. */
94 + int exit_code; /* Child exit code, if dead. */
95 + struct semaphore dead; /* 1=child alive, 0=child dead. */
98 /* If false (default), use round-robin scheduler.
99 If true, use multi-level feedback queue scheduler.
100 Controlled by kernel command-line options "-o mlfqs".
101 Index: src/userprog/exception.c
102 diff -u src/userprog/exception.c~ src/userprog/exception.c
103 --- src/userprog/exception.c~
104 +++ src/userprog/exception.c
105 @@ -150,6 +150,14 @@ page_fault (struct intr_frame *f)
106 write = (f->error_code & PF_W) != 0;
107 user = (f->error_code & PF_U) != 0;
109 + /* Handle bad dereferences from system call implementations. */
112 + f->eip = (void (*) (void)) f->eax;
117 /* To implement virtual memory, delete the rest of the function
118 body, and replace it with code that brings in the page to
119 which fault_addr refers. */
120 Index: src/userprog/process.c
121 diff -u src/userprog/process.c~ src/userprog/process.c
122 --- src/userprog/process.c~
123 +++ src/userprog/process.c
125 #include "threads/init.h"
126 #include "threads/interrupt.h"
127 +#include "threads/malloc.h"
128 #include "threads/palloc.h"
129 #include "threads/thread.h"
130 #include "threads/vaddr.h"
132 static thread_func execute_thread NO_RETURN;
133 -static bool load (const char *cmdline, void (**eip) (void), void **esp);
134 +static bool load (const char *cmd_line, void (**eip) (void), void **esp);
136 +/* Data structure shared between process_execute() in the
137 + invoking thread and execute_thread() in the newly invoked
141 + const char *file_name; /* Program to load. */
142 + struct semaphore load_done; /* "Up"ed when loading complete. */
143 + struct wait_status *wait_status; /* Child process. */
144 + bool success; /* Program successfully loaded? */
147 /* Starts a new thread running a user program loaded from
148 FILE_NAME. The new thread may be scheduled (and may even exit)
149 @@ -27,29 +39,37 @@ static bool load (const char *cmdline, v
151 process_execute (const char *file_name)
154 + struct exec_info exec;
155 + char thread_name[16];
159 - /* Make a copy of FILE_NAME.
160 - Otherwise there's a race between the caller and load(). */
161 - fn_copy = palloc_get_page (0);
162 - if (fn_copy == NULL)
164 - strlcpy (fn_copy, file_name, PGSIZE);
165 + /* Initialize exec_info. */
166 + exec.file_name = file_name;
167 + sema_init (&exec.load_done, 0);
169 /* Create a new thread to execute FILE_NAME. */
170 - tid = thread_create (file_name, PRI_DEFAULT, execute_thread, fn_copy);
171 - if (tid == TID_ERROR)
172 - palloc_free_page (fn_copy);
173 + strlcpy (thread_name, file_name, sizeof thread_name);
174 + strtok_r (thread_name, " ", &save_ptr);
175 + tid = thread_create (thread_name, PRI_DEFAULT, execute_thread, &exec);
176 + if (tid != TID_ERROR)
178 + sema_down (&exec.load_done);
180 + list_push_back (&thread_current ()->children, &exec.wait_status->elem);
188 /* A thread function that loads a user process and starts it
191 -execute_thread (void *file_name_)
192 +execute_thread (void *exec_)
194 - char *file_name = file_name_;
195 + struct exec_info *exec = exec_;
196 struct intr_frame if_;
199 @@ -58,10 +78,29 @@ execute_thread (void *file_name_)
200 if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
202 if_.eflags = FLAG_IF | FLAG_MBS;
203 - success = load (file_name, &if_.eip, &if_.esp);
204 + success = load (exec->file_name, &if_.eip, &if_.esp);
206 + /* Allocate wait_status. */
209 + exec->wait_status = thread_current ()->wait_status
210 + = malloc (sizeof *exec->wait_status);
211 + success = exec->wait_status != NULL;
214 - /* If load failed, quit. */
215 - palloc_free_page (file_name);
216 + /* Initialize wait_status. */
219 + lock_init (&exec->wait_status->lock);
220 + exec->wait_status->ref_cnt = 2;
221 + exec->wait_status->tid = thread_current ()->tid;
222 + exec->wait_status->exit_code = -1;
223 + sema_init (&exec->wait_status->dead, 0);
226 + /* Notify parent thread and clean up. */
227 + exec->success = success;
228 + sema_up (&exec->load_done);
232 @@ -75,18 +113,47 @@ execute_thread (void *file_name_)
236 +/* Releases one reference to CS and, if it is now unreferenced,
239 +release_child (struct wait_status *cs)
243 + lock_acquire (&cs->lock);
244 + new_ref_cnt = --cs->ref_cnt;
245 + lock_release (&cs->lock);
247 + if (new_ref_cnt == 0)
251 /* Waits for thread TID to die and returns its exit status. If
252 it was terminated by the kernel (i.e. killed due to an
253 exception), returns -1. If TID is invalid or if it was not a
254 child of the calling process, or if process_wait() has already
255 been successfully called for the given TID, returns -1
256 - immediately, without waiting.
258 - This function will be implemented in problem 2-2. For now, it
260 + immediately, without waiting. */
262 -process_wait (tid_t child_tid UNUSED)
263 +process_wait (tid_t child_tid)
265 + struct thread *cur = thread_current ();
266 + struct list_elem *e;
268 + for (e = list_begin (&cur->children); e != list_end (&cur->children);
271 + struct wait_status *cs = list_entry (e, struct wait_status, elem);
272 + if (cs->tid == child_tid)
276 + sema_down (&cs->dead);
277 + exit_code = cs->exit_code;
278 + release_child (cs);
285 @@ -95,8 +162,30 @@ void
288 struct thread *cur = thread_current ();
289 + struct list_elem *e, *next;
292 + /* Close executable (and allow writes). */
293 + file_close (cur->bin_file);
295 + /* Notify parent that we're dead. */
296 + if (cur->wait_status != NULL)
298 + struct wait_status *cs = cur->wait_status;
299 + printf ("%s: exit(%d)\n", cur->name, cs->exit_code);
300 + sema_up (&cs->dead);
301 + release_child (cs);
304 + /* Free entries of children list. */
305 + for (e = list_begin (&cur->children); e != list_end (&cur->children);
308 + struct wait_status *cs = list_entry (e, struct wait_status, elem);
309 + next = list_remove (e);
310 + release_child (cs);
313 /* Destroy the current process's page directory and switch back
314 to the kernel-only page directory. */
316 @@ -193,7 +284,7 @@ struct Elf32_Phdr
317 #define PF_W 2 /* Writable. */
318 #define PF_R 4 /* Readable. */
320 -static bool setup_stack (void **esp);
321 +static bool setup_stack (const char *cmd_line, void **esp);
322 static bool validate_segment (const struct Elf32_Phdr *, struct file *);
323 static bool load_segment (struct file *file, off_t ofs, uint8_t *upage,
325 @@ -209,13 +300,15 @@ static bool setup_stack (void **esp);
326 and its initial stack pointer into *ESP.
327 Returns true if successful, false otherwise. */
329 -load (const char *file_name, void (**eip) (void), void **esp)
330 +load (const char *cmd_line, void (**eip) (void), void **esp)
332 struct thread *t = thread_current ();
333 + char file_name[NAME_MAX + 2];
334 struct Elf32_Ehdr ehdr;
335 struct file *file = NULL;
337 bool success = false;
341 /* Allocate and activate page directory. */
342 @@ -224,13 +317,22 @@ load (const char *file_name, void (**eip)
346 + /* Extract file_name from command line. */
347 + while (*cmd_line == ' ')
349 + strlcpy (file_name, cmd_line, sizeof file_name);
350 + cp = strchr (file_name, ' ');
354 /* Open executable file. */
355 - file = filesys_open (file_name);
356 + t->bin_file = file = filesys_open (file_name);
359 printf ("load: %s: open failed\n", file_name);
362 + file_deny_write (file);
364 /* Read and verify executable header. */
365 if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr
366 @@ -284,7 +386,7 @@ load (const char *file_name, void (**eip)
370 - if (!setup_stack (esp))
371 + if (!setup_stack (cmd_line, esp))
375 @@ -294,7 +396,6 @@ load (const char *file_name, void (**eip)
378 /* We arrive here whether the load is successful or not. */
383 @@ -393,10 +494,92 @@ load_segment (struct file *file, const s
387 -/* Create a minimal stack by mapping a zeroed page at the top of
388 - user virtual memory. */
389 +/* Reverse the order of the ARGC pointers to char in ARGV. */
391 +reverse (int argc, char **argv)
393 + for (; argc > 1; argc -= 2, argv++)
395 + char *tmp = argv[0];
396 + argv[0] = argv[argc - 1];
397 + argv[argc - 1] = tmp;
401 +/* Pushes the SIZE bytes in BUF onto the stack in KPAGE, whose
402 + page-relative stack pointer is *OFS, and then adjusts *OFS
403 + appropriately. The bytes pushed are rounded to a 32-bit
406 + If successful, returns a pointer to the newly pushed object.
407 + On failure, returns a null pointer. */
409 +push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size)
411 + size_t padsize = ROUND_UP (size, sizeof (uint32_t));
412 + if (*ofs < padsize)
416 + memcpy (kpage + *ofs + (padsize - size), buf, size);
417 + return kpage + *ofs + (padsize - size);
420 +/* Sets up command line arguments in KPAGE, which will be mapped
421 + to UPAGE in user space. The command line arguments are taken
422 + from CMD_LINE, separated by spaces. Sets *ESP to the initial
423 + stack pointer for the process. */
425 +init_cmd_line (uint8_t *kpage, uint8_t *upage, const char *cmd_line,
428 + size_t ofs = PGSIZE;
429 + char *const null = NULL;
430 + char *cmd_line_copy;
431 + char *karg, *saveptr;
435 + /* Push command line string. */
436 + cmd_line_copy = push (kpage, &ofs, cmd_line, strlen (cmd_line) + 1);
437 + if (cmd_line_copy == NULL)
440 + if (push (kpage, &ofs, &null, sizeof null) == NULL)
443 + /* Parse command line into arguments
444 + and push them in reverse order. */
446 + for (karg = strtok_r (cmd_line_copy, " ", &saveptr); karg != NULL;
447 + karg = strtok_r (NULL, " ", &saveptr))
449 + void *uarg = upage + (karg - (char *) kpage);
450 + if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
455 + /* Reverse the order of the command line arguments. */
456 + argv = (char **) (upage + ofs);
457 + reverse (argc, (char **) (kpage + ofs));
459 + /* Push argv, argc, "return address". */
460 + if (push (kpage, &ofs, &argv, sizeof argv) == NULL
461 + || push (kpage, &ofs, &argc, sizeof argc) == NULL
462 + || push (kpage, &ofs, &null, sizeof null) == NULL)
465 + /* Set initial stack pointer. */
466 + *esp = upage + ofs;
470 +/* Create a minimal stack for T by mapping a page at the
471 + top of user virtual memory. Fills in the page using CMD_LINE
472 + and sets *ESP to the stack pointer. */
474 -setup_stack (void **esp)
475 +setup_stack (const char *cmd_line, void **esp)
478 bool success = false;
479 @@ -404,9 +587,9 @@ setup_stack (void **esp)
480 kpage = palloc_get_page (PAL_USER | PAL_ZERO);
483 - success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true);
486 + uint8_t *upage = ((uint8_t *) PHYS_BASE) - PGSIZE;
487 + if (install_page (upage, kpage, true))
488 + success = init_cmd_line (kpage, upage, cmd_line, esp);
490 palloc_free_page (kpage);
492 Index: src/userprog/syscall.c
493 diff -u src/userprog/syscall.c~ src/userprog/syscall.c
494 --- src/userprog/syscall.c~
495 +++ src/userprog/syscall.c
497 #include "userprog/syscall.h"
500 #include <syscall-nr.h>
501 +#include "userprog/process.h"
502 +#include "userprog/pagedir.h"
503 +#include "devices/input.h"
504 +#include "filesys/filesys.h"
505 +#include "filesys/file.h"
506 +#include "threads/init.h"
507 #include "threads/interrupt.h"
508 +#include "threads/malloc.h"
509 +#include "threads/palloc.h"
510 #include "threads/thread.h"
511 +#include "threads/vaddr.h"
515 +static int sys_halt (void);
516 +static int sys_exit (int status);
517 +static int sys_exec (const char *ufile);
518 +static int sys_wait (tid_t);
519 +static int sys_create (const char *ufile, unsigned initial_size);
520 +static int sys_remove (const char *ufile);
521 +static int sys_open (const char *ufile);
522 +static int sys_filesize (int handle);
523 +static int sys_read (int handle, void *udst_, unsigned size);
524 +static int sys_write (int handle, void *usrc_, unsigned size);
525 +static int sys_seek (int handle, unsigned position);
526 +static int sys_tell (int handle);
527 +static int sys_close (int handle);
529 static void syscall_handler (struct intr_frame *);
531 +static void copy_in (void *, const void *, size_t);
533 +/* Serializes file system operations. */
534 +static struct lock fs_lock;
539 intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall");
540 + lock_init (&fs_lock);
543 +/* System call handler. */
545 +syscall_handler (struct intr_frame *f)
547 + typedef int syscall_function (int, int, int);
549 + /* A system call. */
552 + size_t arg_cnt; /* Number of arguments. */
553 + syscall_function *func; /* Implementation. */
556 + /* Table of system calls. */
557 + static const struct syscall syscall_table[] =
559 + {0, (syscall_function *) sys_halt},
560 + {1, (syscall_function *) sys_exit},
561 + {1, (syscall_function *) sys_exec},
562 + {1, (syscall_function *) sys_wait},
563 + {2, (syscall_function *) sys_create},
564 + {1, (syscall_function *) sys_remove},
565 + {1, (syscall_function *) sys_open},
566 + {1, (syscall_function *) sys_filesize},
567 + {3, (syscall_function *) sys_read},
568 + {3, (syscall_function *) sys_write},
569 + {2, (syscall_function *) sys_seek},
570 + {1, (syscall_function *) sys_tell},
571 + {1, (syscall_function *) sys_close},
574 + const struct syscall *sc;
578 + /* Get the system call. */
579 + copy_in (&call_nr, f->esp, sizeof call_nr);
580 + if (call_nr >= sizeof syscall_table / sizeof *syscall_table)
582 + sc = syscall_table + call_nr;
584 + /* Get the system call arguments. */
585 + ASSERT (sc->arg_cnt <= sizeof args / sizeof *args);
586 + memset (args, 0, sizeof args);
587 + copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * sc->arg_cnt);
589 + /* Execute the system call,
590 + and set the return value. */
591 + f->eax = sc->func (args[0], args[1], args[2]);
594 +/* Returns true if UADDR is a valid, mapped user address,
595 + false otherwise. */
597 +verify_user (const void *uaddr)
599 + return (uaddr < PHYS_BASE
600 + && pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL);
603 +/* Copies a byte from user address USRC to kernel address DST.
604 + USRC must be below PHYS_BASE.
605 + Returns true if successful, false if a segfault occurred. */
607 +get_user (uint8_t *dst, const uint8_t *usrc)
610 + asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
611 + : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
615 +/* Writes BYTE to user address UDST.
616 + UDST must be below PHYS_BASE.
617 + Returns true if successful, false if a segfault occurred. */
619 +put_user (uint8_t *udst, uint8_t byte)
622 + asm ("movl $1f, %%eax; movb %b2, %0; 1:"
623 + : "=m" (*udst), "=&a" (eax) : "r" (byte));
627 +/* Copies SIZE bytes from user address USRC to kernel address
629 + Call thread_exit() if any of the user accesses are invalid. */
631 -syscall_handler (struct intr_frame *f UNUSED)
632 +copy_in (void *dst_, const void *usrc_, size_t size)
634 + uint8_t *dst = dst_;
635 + const uint8_t *usrc = usrc_;
637 + for (; size > 0; size--, dst++, usrc++)
638 + if (usrc >= (uint8_t *) PHYS_BASE || !get_user (dst, usrc))
642 +/* Creates a copy of user string US in kernel memory
643 + and returns it as a page that must be freed with
644 + palloc_free_page().
645 + Truncates the string at PGSIZE bytes in size.
646 + Call thread_exit() if any of the user accesses are invalid. */
648 +copy_in_string (const char *us)
653 + ks = palloc_get_page (0);
657 + for (length = 0; length < PGSIZE; length++)
659 + if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++))
661 + palloc_free_page (ks);
665 + if (ks[length] == '\0')
668 + ks[PGSIZE - 1] = '\0';
672 +/* Halt system call. */
679 +/* Exit system call. */
681 +sys_exit (int exit_code)
683 + thread_current ()->wait_status->exit_code = exit_code;
688 +/* Exec system call. */
690 +sys_exec (const char *ufile)
693 + char *kfile = copy_in_string (ufile);
695 + lock_acquire (&fs_lock);
696 + tid = process_execute (kfile);
697 + lock_release (&fs_lock);
699 + palloc_free_page (kfile);
704 +/* Wait system call. */
706 +sys_wait (tid_t child)
708 + return process_wait (child);
711 +/* Create system call. */
713 +sys_create (const char *ufile, unsigned initial_size)
715 + char *kfile = copy_in_string (ufile);
718 + lock_acquire (&fs_lock);
719 + ok = filesys_create (kfile, initial_size);
720 + lock_release (&fs_lock);
722 + palloc_free_page (kfile);
727 +/* Remove system call. */
729 +sys_remove (const char *ufile)
731 - printf ("system call!\n");
732 + char *kfile = copy_in_string (ufile);
735 + lock_acquire (&fs_lock);
736 + ok = filesys_remove (kfile);
737 + lock_release (&fs_lock);
739 + palloc_free_page (kfile);
744 +/* A file descriptor, for binding a file handle to a file. */
745 +struct file_descriptor
747 + struct list_elem elem; /* List element. */
748 + struct file *file; /* File. */
749 + int handle; /* File handle. */
752 +/* Open system call. */
754 +sys_open (const char *ufile)
756 + char *kfile = copy_in_string (ufile);
757 + struct file_descriptor *fd;
760 + fd = malloc (sizeof *fd);
763 + lock_acquire (&fs_lock);
764 + fd->file = filesys_open (kfile);
765 + if (fd->file != NULL)
767 + struct thread *cur = thread_current ();
768 + handle = fd->handle = cur->next_handle++;
769 + list_push_front (&cur->fds, &fd->elem);
773 + lock_release (&fs_lock);
776 + palloc_free_page (kfile);
780 +/* Returns the file descriptor associated with the given handle.
781 + Terminates the process if HANDLE is not associated with an
783 +static struct file_descriptor *
784 +lookup_fd (int handle)
786 + struct thread *cur = thread_current ();
787 + struct list_elem *e;
789 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
792 + struct file_descriptor *fd;
793 + fd = list_entry (e, struct file_descriptor, elem);
794 + if (fd->handle == handle)
801 +/* Filesize system call. */
803 +sys_filesize (int handle)
805 + struct file_descriptor *fd = lookup_fd (handle);
808 + lock_acquire (&fs_lock);
809 + size = file_length (fd->file);
810 + lock_release (&fs_lock);
815 +/* Read system call. */
817 +sys_read (int handle, void *udst_, unsigned size)
819 + uint8_t *udst = udst_;
820 + struct file_descriptor *fd;
821 + int bytes_read = 0;
823 + /* Handle keyboard reads. */
824 + if (handle == STDIN_FILENO)
826 + for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
827 + if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, input_getc ()))
832 + /* Handle all other reads. */
833 + fd = lookup_fd (handle);
834 + lock_acquire (&fs_lock);
837 + /* How much to read into this page? */
838 + size_t page_left = PGSIZE - pg_ofs (udst);
839 + size_t read_amt = size < page_left ? size : page_left;
842 + /* Check that touching this page is okay. */
843 + if (!verify_user (udst))
845 + lock_release (&fs_lock);
849 + /* Read from file into page. */
850 + retval = file_read (fd->file, udst, read_amt);
853 + if (bytes_read == 0)
857 + bytes_read += retval;
859 + /* If it was a short read we're done. */
860 + if (retval != (off_t) read_amt)
867 + lock_release (&fs_lock);
872 +/* Write system call. */
874 +sys_write (int handle, void *usrc_, unsigned size)
876 + uint8_t *usrc = usrc_;
877 + struct file_descriptor *fd = NULL;
878 + int bytes_written = 0;
880 + /* Lookup up file descriptor. */
881 + if (handle != STDOUT_FILENO)
882 + fd = lookup_fd (handle);
884 + lock_acquire (&fs_lock);
887 + /* How much bytes to write to this page? */
888 + size_t page_left = PGSIZE - pg_ofs (usrc);
889 + size_t write_amt = size < page_left ? size : page_left;
892 + /* Check that we can touch this user page. */
893 + if (!verify_user (usrc))
895 + lock_release (&fs_lock);
899 + /* Do the write. */
900 + if (handle == STDOUT_FILENO)
902 + putbuf (usrc, write_amt);
903 + retval = write_amt;
906 + retval = file_write (fd->file, usrc, write_amt);
909 + if (bytes_written == 0)
910 + bytes_written = -1;
913 + bytes_written += retval;
915 + /* If it was a short write we're done. */
916 + if (retval != (off_t) write_amt)
923 + lock_release (&fs_lock);
925 + return bytes_written;
928 +/* Seek system call. */
930 +sys_seek (int handle, unsigned position)
932 + struct file_descriptor *fd = lookup_fd (handle);
934 + lock_acquire (&fs_lock);
935 + if ((off_t) position >= 0)
936 + file_seek (fd->file, position);
937 + lock_release (&fs_lock);
942 +/* Tell system call. */
944 +sys_tell (int handle)
946 + struct file_descriptor *fd = lookup_fd (handle);
949 + lock_acquire (&fs_lock);
950 + position = file_tell (fd->file);
951 + lock_release (&fs_lock);
956 +/* Close system call. */
958 +sys_close (int handle)
960 + struct file_descriptor *fd = lookup_fd (handle);
961 + lock_acquire (&fs_lock);
962 + file_close (fd->file);
963 + lock_release (&fs_lock);
964 + list_remove (&fd->elem);
969 +/* On thread exit, close all open files. */
973 + struct thread *cur = thread_current ();
974 + struct list_elem *e, *next;
976 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
978 + struct file_descriptor *fd;
979 + fd = list_entry (e, struct file_descriptor, elem);
980 + next = list_next (e);
981 + lock_acquire (&fs_lock);
982 + file_close (fd->file);
983 + lock_release (&fs_lock);
987 Index: src/userprog/syscall.h
988 diff -u src/userprog/syscall.h~ src/userprog/syscall.h
989 --- src/userprog/syscall.h~
990 +++ src/userprog/syscall.h
992 #define USERPROG_SYSCALL_H
994 void syscall_init (void);
995 +void syscall_exit (void);
997 #endif /* userprog/syscall.h */