1 diff --git a/src/threads/thread.c b/src/threads/thread.c
2 index 86614f5..9fa7f1c 100644
3 --- a/src/threads/thread.c
4 +++ b/src/threads/thread.c
6 #include "threads/vaddr.h"
8 #include "userprog/process.h"
9 +#include "userprog/syscall.h"
12 /* Random value for struct thread's `magic' member.
13 @@ -351,7 +352,8 @@ thread_exit (void)
20 /* Remove thread from all threads list, set our status to dying,
21 and schedule another process. That process will destroy us
22 when it calls thread_schedule_tail(). */
23 @@ -608,6 +610,10 @@ init_thread (struct thread *t, const char *name, int priority)
24 strlcpy (t->name, name, sizeof t->name);
25 t->stack = (uint8_t *) t + PGSIZE;
26 t->priority = t->normal_priority = priority;
27 + list_init (&t->children);
28 + t->wait_status = NULL;
29 + list_init (&t->fds);
31 t->magic = THREAD_MAGIC;
32 sema_init (&t->timer_sema, 0);
33 list_init (&t->donors);
34 diff --git a/src/threads/thread.h b/src/threads/thread.h
35 index 6601963..2c85d88 100644
36 --- a/src/threads/thread.h
37 +++ b/src/threads/thread.h
38 @@ -101,6 +101,10 @@ struct thread
39 fixed_point_t recent_cpu; /* Recent amount of CPU time. */
40 struct list_elem allelem; /* List element for all threads list. */
42 + /* Owned by process.c. */
43 + struct wait_status *wait_status; /* This process's completion status. */
44 + struct list children; /* Completion status of children. */
46 /* Shared between thread.c and synch.c. */
47 struct list_elem elem; /* List element. */
49 @@ -113,11 +117,31 @@ struct thread
50 /* Owned by userprog/process.c. */
51 uint32_t *pagedir; /* Page directory. */
53 + struct file *bin_file; /* Executable. */
55 + /* Owned by syscall.c. */
56 + struct list fds; /* List of file descriptors. */
57 + int next_handle; /* Next handle value. */
59 /* Owned by thread.c. */
60 unsigned magic; /* Detects stack overflow. */
63 +/* Tracks the completion of a process.
64 + Reference held by both the parent, in its `children' list,
65 + and by the child, in its `wait_status' pointer. */
68 + struct list_elem elem; /* `children' list element. */
69 + struct lock lock; /* Protects ref_cnt. */
70 + int ref_cnt; /* 2=child and parent both alive,
71 + 1=either child or parent alive,
72 + 0=child and parent both dead. */
73 + tid_t tid; /* Child thread id. */
74 + int exit_code; /* Child exit code, if dead. */
75 + struct semaphore dead; /* 1=child alive, 0=child dead. */
78 /* If false (default), use round-robin scheduler.
79 If true, use multi-level feedback queue scheduler.
80 Controlled by kernel command-line option "-o mlfqs". */
81 diff --git a/src/userprog/exception.c b/src/userprog/exception.c
82 index 19aca12..3682478 100644
83 --- a/src/userprog/exception.c
84 +++ b/src/userprog/exception.c
85 @@ -148,6 +148,14 @@ page_fault (struct intr_frame *f)
86 write = (f->error_code & PF_W) != 0;
87 user = (f->error_code & PF_U) != 0;
89 + /* Handle bad dereferences from system call implementations. */
92 + f->eip = (void (*) (void)) f->eax;
97 /* To implement virtual memory, delete the rest of the function
98 body, and replace it with code that brings in the page to
99 which fault_addr refers. */
100 diff --git a/src/userprog/process.c b/src/userprog/process.c
101 index c0e5215..06ff27e 100644
102 --- a/src/userprog/process.c
103 +++ b/src/userprog/process.c
105 #include "threads/flags.h"
106 #include "threads/init.h"
107 #include "threads/interrupt.h"
108 +#include "threads/malloc.h"
109 #include "threads/palloc.h"
110 #include "threads/thread.h"
111 #include "threads/vaddr.h"
113 static thread_func start_process NO_RETURN;
114 -static bool load (const char *cmdline, void (**eip) (void), void **esp);
115 +static bool load (const char *cmd_line, void (**eip) (void), void **esp);
117 +/* Data structure shared between process_execute() in the
118 + invoking thread and start_process() in the newly invoked
122 + const char *file_name; /* Program to load. */
123 + struct semaphore load_done; /* "Up"ed when loading complete. */
124 + struct wait_status *wait_status; /* Child process. */
125 + bool success; /* Program successfully loaded? */
128 /* Starts a new thread running a user program loaded from
129 FILENAME. The new thread may be scheduled (and may even exit)
130 @@ -28,29 +40,37 @@ static bool load (const char *cmdline, void (**eip) (void), void **esp);
132 process_execute (const char *file_name)
135 + struct exec_info exec;
136 + char thread_name[16];
140 - /* Make a copy of FILE_NAME.
141 - Otherwise there's a race between the caller and load(). */
142 - fn_copy = palloc_get_page (0);
143 - if (fn_copy == NULL)
145 - strlcpy (fn_copy, file_name, PGSIZE);
146 + /* Initialize exec_info. */
147 + exec.file_name = file_name;
148 + sema_init (&exec.load_done, 0);
150 /* Create a new thread to execute FILE_NAME. */
151 - tid = thread_create (file_name, PRI_DEFAULT, start_process, fn_copy);
152 - if (tid == TID_ERROR)
153 - palloc_free_page (fn_copy);
154 + strlcpy (thread_name, file_name, sizeof thread_name);
155 + strtok_r (thread_name, " ", &save_ptr);
156 + tid = thread_create (thread_name, PRI_DEFAULT, start_process, &exec);
157 + if (tid != TID_ERROR)
159 + sema_down (&exec.load_done);
161 + list_push_back (&thread_current ()->children, &exec.wait_status->elem);
169 /* A thread function that loads a user process and starts it
172 -start_process (void *file_name_)
173 +start_process (void *exec_)
175 - char *file_name = file_name_;
176 + struct exec_info *exec = exec_;
177 struct intr_frame if_;
180 @@ -59,10 +79,29 @@ start_process (void *file_name_)
181 if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
183 if_.eflags = FLAG_IF | FLAG_MBS;
184 - success = load (file_name, &if_.eip, &if_.esp);
185 + success = load (exec->file_name, &if_.eip, &if_.esp);
187 + /* Allocate wait_status. */
190 + exec->wait_status = thread_current ()->wait_status
191 + = malloc (sizeof *exec->wait_status);
192 + success = exec->wait_status != NULL;
195 - /* If load failed, quit. */
196 - palloc_free_page (file_name);
197 + /* Initialize wait_status. */
200 + lock_init (&exec->wait_status->lock);
201 + exec->wait_status->ref_cnt = 2;
202 + exec->wait_status->tid = thread_current ()->tid;
203 + exec->wait_status->exit_code = -1;
204 + sema_init (&exec->wait_status->dead, 0);
207 + /* Notify parent thread and clean up. */
208 + exec->success = success;
209 + sema_up (&exec->load_done);
213 @@ -76,18 +115,47 @@ start_process (void *file_name_)
217 +/* Releases one reference to CS and, if it is now unreferenced,
220 +release_child (struct wait_status *cs)
224 + lock_acquire (&cs->lock);
225 + new_ref_cnt = --cs->ref_cnt;
226 + lock_release (&cs->lock);
228 + if (new_ref_cnt == 0)
232 /* Waits for thread TID to die and returns its exit status. If
233 it was terminated by the kernel (i.e. killed due to an
234 exception), returns -1. If TID is invalid or if it was not a
235 child of the calling process, or if process_wait() has already
236 been successfully called for the given TID, returns -1
237 - immediately, without waiting.
239 - This function will be implemented in problem 2-2. For now, it
241 + immediately, without waiting. */
243 -process_wait (tid_t child_tid UNUSED)
244 +process_wait (tid_t child_tid)
246 + struct thread *cur = thread_current ();
247 + struct list_elem *e;
249 + for (e = list_begin (&cur->children); e != list_end (&cur->children);
252 + struct wait_status *cs = list_entry (e, struct wait_status, elem);
253 + if (cs->tid == child_tid)
257 + sema_down (&cs->dead);
258 + exit_code = cs->exit_code;
259 + release_child (cs);
266 @@ -96,8 +164,30 @@ void
269 struct thread *cur = thread_current ();
270 + struct list_elem *e, *next;
273 + /* Close executable (and allow writes). */
274 + file_close (cur->bin_file);
276 + /* Notify parent that we're dead. */
277 + if (cur->wait_status != NULL)
279 + struct wait_status *cs = cur->wait_status;
280 + printf ("%s: exit(%d)\n", cur->name, cs->exit_code);
281 + sema_up (&cs->dead);
282 + release_child (cs);
285 + /* Free entries of children list. */
286 + for (e = list_begin (&cur->children); e != list_end (&cur->children);
289 + struct wait_status *cs = list_entry (e, struct wait_status, elem);
290 + next = list_remove (e);
291 + release_child (cs);
294 /* Destroy the current process's page directory and switch back
295 to the kernel-only page directory. */
297 @@ -195,7 +285,7 @@ struct Elf32_Phdr
298 #define PF_W 2 /* Writable. */
299 #define PF_R 4 /* Readable. */
301 -static bool setup_stack (void **esp);
302 +static bool setup_stack (const char *cmd_line, void **esp);
303 static bool validate_segment (const struct Elf32_Phdr *, struct file *);
304 static bool load_segment (struct file *file, off_t ofs, uint8_t *upage,
305 uint32_t read_bytes, uint32_t zero_bytes,
306 @@ -206,13 +296,15 @@ static bool load_segment (struct file *file, off_t ofs, uint8_t *upage,
307 and its initial stack pointer into *ESP.
308 Returns true if successful, false otherwise. */
310 -load (const char *file_name, void (**eip) (void), void **esp)
311 +load (const char *cmd_line, void (**eip) (void), void **esp)
313 struct thread *t = thread_current ();
314 + char file_name[NAME_MAX + 2];
315 struct Elf32_Ehdr ehdr;
316 struct file *file = NULL;
318 bool success = false;
322 /* Allocate and activate page directory. */
323 @@ -221,13 +313,22 @@ load (const char *file_name, void (**eip) (void), void **esp)
327 + /* Extract file_name from command line. */
328 + while (*cmd_line == ' ')
330 + strlcpy (file_name, cmd_line, sizeof file_name);
331 + cp = strchr (file_name, ' ');
335 /* Open executable file. */
336 - file = filesys_open (file_name);
337 + t->bin_file = file = filesys_open (file_name);
340 printf ("load: %s: open failed\n", file_name);
343 + file_deny_write (file);
345 /* Read and verify executable header. */
346 if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr
347 @@ -302,7 +403,7 @@ load (const char *file_name, void (**eip) (void), void **esp)
351 - if (!setup_stack (esp))
352 + if (!setup_stack (cmd_line, esp))
356 @@ -312,7 +413,6 @@ load (const char *file_name, void (**eip) (void), void **esp)
359 /* We arrive here whether the load is successful or not. */
364 @@ -424,10 +524,92 @@ load_segment (struct file *file, off_t ofs, uint8_t *upage,
368 -/* Create a minimal stack by mapping a zeroed page at the top of
369 - user virtual memory. */
370 +/* Reverse the order of the ARGC pointers to char in ARGV. */
372 +reverse (int argc, char **argv)
374 + for (; argc > 1; argc -= 2, argv++)
376 + char *tmp = argv[0];
377 + argv[0] = argv[argc - 1];
378 + argv[argc - 1] = tmp;
382 +/* Pushes the SIZE bytes in BUF onto the stack in KPAGE, whose
383 + page-relative stack pointer is *OFS, and then adjusts *OFS
384 + appropriately. The bytes pushed are rounded to a 32-bit
387 + If successful, returns a pointer to the newly pushed object.
388 + On failure, returns a null pointer. */
390 +push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size)
392 + size_t padsize = ROUND_UP (size, sizeof (uint32_t));
393 + if (*ofs < padsize)
397 + memcpy (kpage + *ofs + (padsize - size), buf, size);
398 + return kpage + *ofs + (padsize - size);
401 +/* Sets up command line arguments in KPAGE, which will be mapped
402 + to UPAGE in user space. The command line arguments are taken
403 + from CMD_LINE, separated by spaces. Sets *ESP to the initial
404 + stack pointer for the process. */
406 +init_cmd_line (uint8_t *kpage, uint8_t *upage, const char *cmd_line,
409 + size_t ofs = PGSIZE;
410 + char *const null = NULL;
411 + char *cmd_line_copy;
412 + char *karg, *saveptr;
416 + /* Push command line string. */
417 + cmd_line_copy = push (kpage, &ofs, cmd_line, strlen (cmd_line) + 1);
418 + if (cmd_line_copy == NULL)
421 + if (push (kpage, &ofs, &null, sizeof null) == NULL)
424 + /* Parse command line into arguments
425 + and push them in reverse order. */
427 + for (karg = strtok_r (cmd_line_copy, " ", &saveptr); karg != NULL;
428 + karg = strtok_r (NULL, " ", &saveptr))
430 + void *uarg = upage + (karg - (char *) kpage);
431 + if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
436 + /* Reverse the order of the command line arguments. */
437 + argv = (char **) (upage + ofs);
438 + reverse (argc, (char **) (kpage + ofs));
440 + /* Push argv, argc, "return address". */
441 + if (push (kpage, &ofs, &argv, sizeof argv) == NULL
442 + || push (kpage, &ofs, &argc, sizeof argc) == NULL
443 + || push (kpage, &ofs, &null, sizeof null) == NULL)
446 + /* Set initial stack pointer. */
447 + *esp = upage + ofs;
451 +/* Create a minimal stack for T by mapping a page at the
452 + top of user virtual memory. Fills in the page using CMD_LINE
453 + and sets *ESP to the stack pointer. */
455 -setup_stack (void **esp)
456 +setup_stack (const char *cmd_line, void **esp)
459 bool success = false;
460 @@ -435,9 +617,9 @@ setup_stack (void **esp)
461 kpage = palloc_get_page (PAL_USER | PAL_ZERO);
464 - success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true);
467 + uint8_t *upage = ((uint8_t *) PHYS_BASE) - PGSIZE;
468 + if (install_page (upage, kpage, true))
469 + success = init_cmd_line (kpage, upage, cmd_line, esp);
471 palloc_free_page (kpage);
473 diff --git a/src/userprog/syscall.c b/src/userprog/syscall.c
474 index 370c89b..ef31316 100644
475 --- a/src/userprog/syscall.c
476 +++ b/src/userprog/syscall.c
478 #include "userprog/syscall.h"
481 #include <syscall-nr.h>
482 +#include "userprog/process.h"
483 +#include "userprog/pagedir.h"
484 +#include "devices/input.h"
485 +#include "devices/shutdown.h"
486 +#include "filesys/filesys.h"
487 +#include "filesys/file.h"
488 #include "threads/interrupt.h"
489 +#include "threads/malloc.h"
490 +#include "threads/palloc.h"
491 #include "threads/thread.h"
493 +#include "threads/vaddr.h"
496 +static int sys_halt (void);
497 +static int sys_exit (int status);
498 +static int sys_exec (const char *ufile);
499 +static int sys_wait (tid_t);
500 +static int sys_create (const char *ufile, unsigned initial_size);
501 +static int sys_remove (const char *ufile);
502 +static int sys_open (const char *ufile);
503 +static int sys_filesize (int handle);
504 +static int sys_read (int handle, void *udst_, unsigned size);
505 +static int sys_write (int handle, void *usrc_, unsigned size);
506 +static int sys_seek (int handle, unsigned position);
507 +static int sys_tell (int handle);
508 +static int sys_close (int handle);
510 static void syscall_handler (struct intr_frame *);
512 +static void copy_in (void *, const void *, size_t);
514 +/* Serializes file system operations. */
515 +static struct lock fs_lock;
520 intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall");
521 + lock_init (&fs_lock);
524 +/* System call handler. */
526 +syscall_handler (struct intr_frame *f)
528 + typedef int syscall_function (int, int, int);
530 + /* A system call. */
533 + size_t arg_cnt; /* Number of arguments. */
534 + syscall_function *func; /* Implementation. */
537 + /* Table of system calls. */
538 + static const struct syscall syscall_table[] =
540 + {0, (syscall_function *) sys_halt},
541 + {1, (syscall_function *) sys_exit},
542 + {1, (syscall_function *) sys_exec},
543 + {1, (syscall_function *) sys_wait},
544 + {2, (syscall_function *) sys_create},
545 + {1, (syscall_function *) sys_remove},
546 + {1, (syscall_function *) sys_open},
547 + {1, (syscall_function *) sys_filesize},
548 + {3, (syscall_function *) sys_read},
549 + {3, (syscall_function *) sys_write},
550 + {2, (syscall_function *) sys_seek},
551 + {1, (syscall_function *) sys_tell},
552 + {1, (syscall_function *) sys_close},
555 + const struct syscall *sc;
559 + /* Get the system call. */
560 + copy_in (&call_nr, f->esp, sizeof call_nr);
561 + if (call_nr >= sizeof syscall_table / sizeof *syscall_table)
563 + sc = syscall_table + call_nr;
565 + /* Get the system call arguments. */
566 + ASSERT (sc->arg_cnt <= sizeof args / sizeof *args);
567 + memset (args, 0, sizeof args);
568 + copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * sc->arg_cnt);
570 + /* Execute the system call,
571 + and set the return value. */
572 + f->eax = sc->func (args[0], args[1], args[2]);
575 +/* Returns true if UADDR is a valid, mapped user address,
576 + false otherwise. */
578 +verify_user (const void *uaddr)
580 + return (uaddr < PHYS_BASE
581 + && pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL);
584 +/* Copies a byte from user address USRC to kernel address DST.
585 + USRC must be below PHYS_BASE.
586 + Returns true if successful, false if a segfault occurred. */
588 +get_user (uint8_t *dst, const uint8_t *usrc)
591 + asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
592 + : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
596 +/* Writes BYTE to user address UDST.
597 + UDST must be below PHYS_BASE.
598 + Returns true if successful, false if a segfault occurred. */
600 +put_user (uint8_t *udst, uint8_t byte)
603 + asm ("movl $1f, %%eax; movb %b2, %0; 1:"
604 + : "=m" (*udst), "=&a" (eax) : "q" (byte));
608 +/* Copies SIZE bytes from user address USRC to kernel address
610 + Call thread_exit() if any of the user accesses are invalid. */
612 -syscall_handler (struct intr_frame *f UNUSED)
613 +copy_in (void *dst_, const void *usrc_, size_t size)
615 + uint8_t *dst = dst_;
616 + const uint8_t *usrc = usrc_;
618 + for (; size > 0; size--, dst++, usrc++)
619 + if (usrc >= (uint8_t *) PHYS_BASE || !get_user (dst, usrc))
623 +/* Creates a copy of user string US in kernel memory
624 + and returns it as a page that must be freed with
625 + palloc_free_page().
626 + Truncates the string at PGSIZE bytes in size.
627 + Call thread_exit() if any of the user accesses are invalid. */
629 +copy_in_string (const char *us)
634 + ks = palloc_get_page (0);
638 + for (length = 0; length < PGSIZE; length++)
640 + if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++))
642 + palloc_free_page (ks);
646 + if (ks[length] == '\0')
649 + ks[PGSIZE - 1] = '\0';
653 +/* Halt system call. */
657 + shutdown_power_off ();
660 +/* Exit system call. */
662 +sys_exit (int exit_code)
664 + thread_current ()->wait_status->exit_code = exit_code;
669 +/* Exec system call. */
671 +sys_exec (const char *ufile)
674 + char *kfile = copy_in_string (ufile);
676 + lock_acquire (&fs_lock);
677 + tid = process_execute (kfile);
678 + lock_release (&fs_lock);
680 + palloc_free_page (kfile);
685 +/* Wait system call. */
687 +sys_wait (tid_t child)
689 + return process_wait (child);
692 +/* Create system call. */
694 +sys_create (const char *ufile, unsigned initial_size)
696 + char *kfile = copy_in_string (ufile);
699 + lock_acquire (&fs_lock);
700 + ok = filesys_create (kfile, initial_size);
701 + lock_release (&fs_lock);
703 + palloc_free_page (kfile);
708 +/* Remove system call. */
710 +sys_remove (const char *ufile)
712 - printf ("system call!\n");
713 + char *kfile = copy_in_string (ufile);
716 + lock_acquire (&fs_lock);
717 + ok = filesys_remove (kfile);
718 + lock_release (&fs_lock);
720 + palloc_free_page (kfile);
725 +/* A file descriptor, for binding a file handle to a file. */
726 +struct file_descriptor
728 + struct list_elem elem; /* List element. */
729 + struct file *file; /* File. */
730 + int handle; /* File handle. */
733 +/* Open system call. */
735 +sys_open (const char *ufile)
737 + char *kfile = copy_in_string (ufile);
738 + struct file_descriptor *fd;
741 + fd = malloc (sizeof *fd);
744 + lock_acquire (&fs_lock);
745 + fd->file = filesys_open (kfile);
746 + if (fd->file != NULL)
748 + struct thread *cur = thread_current ();
749 + handle = fd->handle = cur->next_handle++;
750 + list_push_front (&cur->fds, &fd->elem);
754 + lock_release (&fs_lock);
757 + palloc_free_page (kfile);
761 +/* Returns the file descriptor associated with the given handle.
762 + Terminates the process if HANDLE is not associated with an
764 +static struct file_descriptor *
765 +lookup_fd (int handle)
767 + struct thread *cur = thread_current ();
768 + struct list_elem *e;
770 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
773 + struct file_descriptor *fd;
774 + fd = list_entry (e, struct file_descriptor, elem);
775 + if (fd->handle == handle)
782 +/* Filesize system call. */
784 +sys_filesize (int handle)
786 + struct file_descriptor *fd = lookup_fd (handle);
789 + lock_acquire (&fs_lock);
790 + size = file_length (fd->file);
791 + lock_release (&fs_lock);
796 +/* Read system call. */
798 +sys_read (int handle, void *udst_, unsigned size)
800 + uint8_t *udst = udst_;
801 + struct file_descriptor *fd;
802 + int bytes_read = 0;
804 + /* Handle keyboard reads. */
805 + if (handle == STDIN_FILENO)
807 + for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
808 + if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, input_getc ()))
813 + /* Handle all other reads. */
814 + fd = lookup_fd (handle);
815 + lock_acquire (&fs_lock);
818 + /* How much to read into this page? */
819 + size_t page_left = PGSIZE - pg_ofs (udst);
820 + size_t read_amt = size < page_left ? size : page_left;
823 + /* Check that touching this page is okay. */
824 + if (!verify_user (udst))
826 + lock_release (&fs_lock);
830 + /* Read from file into page. */
831 + retval = file_read (fd->file, udst, read_amt);
834 + if (bytes_read == 0)
838 + bytes_read += retval;
840 + /* If it was a short read we're done. */
841 + if (retval != (off_t) read_amt)
848 + lock_release (&fs_lock);
853 +/* Write system call. */
855 +sys_write (int handle, void *usrc_, unsigned size)
857 + uint8_t *usrc = usrc_;
858 + struct file_descriptor *fd = NULL;
859 + int bytes_written = 0;
861 + /* Lookup up file descriptor. */
862 + if (handle != STDOUT_FILENO)
863 + fd = lookup_fd (handle);
865 + lock_acquire (&fs_lock);
868 + /* How much bytes to write to this page? */
869 + size_t page_left = PGSIZE - pg_ofs (usrc);
870 + size_t write_amt = size < page_left ? size : page_left;
873 + /* Check that we can touch this user page. */
874 + if (!verify_user (usrc))
876 + lock_release (&fs_lock);
880 + /* Do the write. */
881 + if (handle == STDOUT_FILENO)
883 + putbuf (usrc, write_amt);
884 + retval = write_amt;
887 + retval = file_write (fd->file, usrc, write_amt);
890 + if (bytes_written == 0)
891 + bytes_written = -1;
894 + bytes_written += retval;
896 + /* If it was a short write we're done. */
897 + if (retval != (off_t) write_amt)
904 + lock_release (&fs_lock);
906 + return bytes_written;
909 +/* Seek system call. */
911 +sys_seek (int handle, unsigned position)
913 + struct file_descriptor *fd = lookup_fd (handle);
915 + lock_acquire (&fs_lock);
916 + if ((off_t) position >= 0)
917 + file_seek (fd->file, position);
918 + lock_release (&fs_lock);
923 +/* Tell system call. */
925 +sys_tell (int handle)
927 + struct file_descriptor *fd = lookup_fd (handle);
930 + lock_acquire (&fs_lock);
931 + position = file_tell (fd->file);
932 + lock_release (&fs_lock);
937 +/* Close system call. */
939 +sys_close (int handle)
941 + struct file_descriptor *fd = lookup_fd (handle);
942 + lock_acquire (&fs_lock);
943 + file_close (fd->file);
944 + lock_release (&fs_lock);
945 + list_remove (&fd->elem);
950 +/* On thread exit, close all open files. */
954 + struct thread *cur = thread_current ();
955 + struct list_elem *e, *next;
957 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
959 + struct file_descriptor *fd;
960 + fd = list_entry (e, struct file_descriptor, elem);
961 + next = list_next (e);
962 + lock_acquire (&fs_lock);
963 + file_close (fd->file);
964 + lock_release (&fs_lock);
968 diff --git a/src/userprog/syscall.h b/src/userprog/syscall.h
969 index 9059096..9d156f0 100644
970 --- a/src/userprog/syscall.h
971 +++ b/src/userprog/syscall.h
973 #define USERPROG_SYSCALL_H
975 void syscall_init (void);
976 +void syscall_exit (void);
978 #endif /* userprog/syscall.h */