2 ===================================================================
3 RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/constants.h,v
4 retrieving revision 1.4
5 diff -u -p -r1.4 constants.h
6 --- src/constants.h 19 Oct 2004 17:37:30 -0000 1.4
7 +++ src/constants.h 1 Jan 2005 02:13:41 -0000
9 /*#define MACRONAME 1 */
11 /* Uncomment if if you've implemented thread_join(). */
12 -/*#define THREAD_JOIN_IMPLEMENTED 1*/
13 +#define THREAD_JOIN_IMPLEMENTED 1
14 Index: src/threads/synch.c
15 ===================================================================
16 RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/threads/synch.c,v
17 retrieving revision 1.15
18 diff -u -p -r1.15 synch.c
19 --- src/threads/synch.c 31 Dec 2004 21:13:38 -0000 1.15
20 +++ src/threads/synch.c 1 Jan 2005 02:13:41 -0000
21 @@ -330,3 +330,45 @@ cond_name (const struct condition *cond)
26 +/* Initializes LATCH and names it NAME (for debugging purposes).
27 + A latch is a boolean condition. Until it is released for the
28 + first time, all threads block attempting to acquire. After it
29 + is released once, all ongoing and subsequent acquisitions
30 + "fall through" immediately. Releases after the first have no
31 + additional effect. */
33 +latch_init (struct latch *latch, const char *name)
35 + latch->released = false;
36 + lock_init (&latch->monitor_lock, name);
37 + cond_init (&latch->rel_cond, name);
40 +/* Acquires LATCH, blocking until it is released for the first
43 +latch_acquire (struct latch *latch)
45 + lock_acquire (&latch->monitor_lock);
46 + if (!latch->released)
48 + cond_wait (&latch->rel_cond, &latch->monitor_lock);
49 + ASSERT (latch->released);
51 + lock_release (&latch->monitor_lock);
54 +/* Releases LATCH, causing all ongoing and subsequent
55 + acquisitions to pass through immediately. */
57 +latch_release (struct latch *latch)
59 + lock_acquire (&latch->monitor_lock);
60 + if (!latch->released)
62 + latch->released = true;
63 + cond_signal (&latch->rel_cond, &latch->monitor_lock);
65 + lock_release (&latch->monitor_lock);
67 Index: src/threads/synch.h
68 ===================================================================
69 RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/threads/synch.h,v
70 retrieving revision 1.7
71 diff -u -p -r1.7 synch.h
72 --- src/threads/synch.h 29 Sep 2004 01:04:09 -0000 1.7
73 +++ src/threads/synch.h 1 Jan 2005 02:13:41 -0000
74 @@ -44,4 +44,16 @@ void cond_signal (struct condition *, st
75 void cond_broadcast (struct condition *, struct lock *);
76 const char *cond_name (const struct condition *);
81 + bool released; /* Released yet? */
82 + struct lock monitor_lock; /* Monitor lock. */
83 + struct condition rel_cond; /* Signaled when released. */
86 +void latch_init (struct latch *, const char *);
87 +void latch_acquire (struct latch *);
88 +void latch_release (struct latch *);
90 #endif /* threads/synch.h */
91 Index: src/threads/thread.c
92 ===================================================================
93 RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/threads/thread.c,v
94 retrieving revision 1.48
95 diff -u -p -r1.48 thread.c
96 --- src/threads/thread.c 9 Oct 2004 18:01:37 -0000 1.48
97 +++ src/threads/thread.c 1 Jan 2005 02:13:42 -0000
99 #include "threads/synch.h"
101 #include "userprog/process.h"
102 +#include "userprog/syscall.h"
105 /* Random value for struct thread's `magic' member.
106 @@ -81,6 +82,7 @@ thread_init (void)
107 init_thread (initial_thread, "main", PRI_DEFAULT);
108 initial_thread->status = THREAD_RUNNING;
109 initial_thread->tid = allocate_tid ();
110 + sema_up (&initial_thread->can_die);
113 /* Starts preemptive thread scheduling by enabling interrupts.
114 @@ -149,6 +151,7 @@ thread_create (const char *name, int pri
115 /* Initialize thread. */
116 init_thread (t, name, priority);
117 tid = t->tid = allocate_tid ();
118 + list_push_back (&thread_current ()->children, &t->children_elem);
120 /* Stack frame for kernel_thread(). */
121 kf = alloc_frame (t, sizeof *kf);
122 @@ -241,16 +244,36 @@ thread_tid (void)
126 + struct thread *t = thread_current ();
127 + list_elem *e, *next;
129 ASSERT (!intr_context ());
136 + /* Notify our parent that we're dying. */
137 + latch_release (&t->ready_to_die);
139 + /* Notify our children that they can die. */
140 + for (e = list_begin (&t->children); e != list_end (&t->children);
143 + struct thread *child = list_entry (e, struct thread, children_elem);
144 + next = list_next (e);
146 + sema_up (&child->can_die);
149 + /* Wait until our parent is ready for us to die. */
150 + sema_down (&t->can_die);
152 /* Just set our status to dying and schedule another process.
153 We will be destroyed during the call to schedule_tail(). */
155 - thread_current ()->status = THREAD_DYING;
156 + t->status = THREAD_DYING;
160 @@ -300,6 +323,26 @@ kernel_thread (thread_func *function, vo
161 function (aux); /* Execute the thread function. */
162 thread_exit (); /* If function() returns, kill the thread. */
165 +/* Waits for thread with tid CHILD_TID to die. */
167 +thread_join (tid_t child_tid)
169 + struct thread *cur = thread_current ();
172 + for (e = list_begin (&cur->children); e != list_end (&cur->children); )
174 + struct thread *child = list_entry (e, struct thread, children_elem);
176 + if (child->tid == child_tid)
178 + latch_acquire (&child->ready_to_die);
179 + return child->exit_code;
185 /* Returns the running thread. */
187 @@ -336,6 +379,12 @@ init_thread (struct thread *t, const cha
188 strlcpy (t->name, name, sizeof t->name);
189 t->stack = (uint8_t *) t + PGSIZE;
190 t->priority = priority;
191 + latch_init (&t->ready_to_die, "ready-to-die");
192 + sema_init (&t->can_die, 0, "can-die");
193 + list_init (&t->children);
195 + list_init (&t->fds);
196 + t->next_handle = 2;
197 t->magic = THREAD_MAGIC;
200 Index: src/threads/thread.h
201 ===================================================================
202 RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/threads/thread.h,v
203 retrieving revision 1.28
204 diff -u -p -r1.28 thread.h
205 --- src/threads/thread.h 29 Sep 2004 01:04:20 -0000 1.28
206 +++ src/threads/thread.h 1 Jan 2005 02:13:42 -0000
211 +#include "threads/synch.h"
213 /* States in a thread's life cycle. */
215 @@ -89,12 +90,23 @@ struct thread
216 uint8_t *stack; /* Saved stack pointer. */
217 int priority; /* Priority. */
219 + /* Members for implementing thread_join(). */
220 + struct latch ready_to_die; /* Release when thread about to die. */
221 + struct semaphore can_die; /* Up when thread allowed to die. */
222 + struct list children; /* List of child threads. */
223 + list_elem children_elem; /* Element of `children' list. */
224 + int exit_code; /* Return status. */
226 /* Shared between thread.c and synch.c. */
227 list_elem elem; /* List element. */
230 /* Owned by userprog/process.c. */
231 uint32_t *pagedir; /* Page directory. */
233 + /* Owned by syscall.c. */
234 + struct list fds; /* List of file descriptors. */
235 + int next_handle; /* Next handle value. */
238 /* Owned by thread.c. */
239 @@ -120,7 +132,7 @@ void thread_exit (void) NO_RETURN;
240 void thread_yield (void);
242 /* This function will be implemented in problem 1-2. */
243 -void thread_join (tid_t);
244 +int thread_join (tid_t);
246 /* These functions will be implemented in problem 1-3. */
247 void thread_set_priority (int);
248 Index: src/userprog/exception.c
249 ===================================================================
250 RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/userprog/exception.c,v
251 retrieving revision 1.10
252 diff -u -p -r1.10 exception.c
253 --- src/userprog/exception.c 26 Sep 2004 21:15:17 -0000 1.10
254 +++ src/userprog/exception.c 1 Jan 2005 02:13:42 -0000
255 @@ -147,6 +147,14 @@ page_fault (struct intr_frame *f)
256 write = (f->error_code & PF_W) != 0;
257 user = (f->error_code & PF_U) != 0;
259 + /* Handle bad dereferences from system call implementations. */
262 + f->eip = (void (*) (void)) f->eax;
267 /* To implement virtual memory, delete the rest of the function
268 body, and replace it with code that brings in the page to
269 which fault_addr refers. */
270 Index: src/userprog/process.c
271 ===================================================================
272 RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/userprog/process.c,v
273 retrieving revision 1.6
274 diff -u -p -r1.6 process.c
275 --- src/userprog/process.c 15 Dec 2004 02:32:02 -0000 1.6
276 +++ src/userprog/process.c 1 Jan 2005 02:13:43 -0000
278 #include "threads/thread.h"
280 static thread_func execute_thread NO_RETURN;
281 -static bool load (const char *cmdline, void (**eip) (void), void **esp);
282 +static bool load (const char *cmd_line, void (**eip) (void), void **esp);
284 +/* Data structure shared between process_execute() in the
285 + invoking thread and execute_thread() in the newly invoked
289 + const char *filename; /* Program to load. */
290 + struct semaphore load_done; /* "Up"ed when loading complete. */
291 + bool success; /* True if program successfully loaded. */
294 /* Starts a new thread running a user program loaded from
295 FILENAME. The new thread may be scheduled before
296 @@ -26,31 +36,32 @@ static bool load (const char *cmdline, v
298 process_execute (const char *filename)
301 + struct exec_info exec;
304 - /* Make a copy of FILENAME.
305 - Otherwise there's a race between the caller and load(). */
306 - fn_copy = palloc_get_page (0);
307 - if (fn_copy == NULL)
309 - strlcpy (fn_copy, filename, PGSIZE);
310 + /* Initialize exec_info. */
311 + exec.filename = filename;
312 + sema_init (&exec.load_done, 0, "load done");
314 /* Create a new thread to execute FILENAME. */
315 - tid = thread_create (filename, PRI_DEFAULT, execute_thread, fn_copy);
316 - if (tid == TID_ERROR)
317 - palloc_free_page (fn_copy);
318 + tid = thread_create (filename, PRI_DEFAULT, execute_thread, &exec);
319 + if (tid != TID_ERROR)
321 + sema_down (&exec.load_done);
328 /* A thread function that loads a user process and starts it
331 -execute_thread (void *filename_)
332 +execute_thread (void *exec_)
334 - char *filename = filename_;
335 + struct exec_info *exec = exec_;
336 struct intr_frame if_;
339 /* Initialize interrupt frame and load executable. */
340 memset (&if_, 0, sizeof if_);
341 @@ -59,11 +69,9 @@ execute_thread (void *filename_)
343 if_.eflags = FLAG_IF | FLAG_MBS;
345 - success = load (filename, &if_.eip, &if_.esp);
347 - /* If load failed, quit. */
348 - palloc_free_page (filename);
349 + success = exec->success = load (exec->filename, &if_.eip, &if_.esp);
350 + sema_up (&exec->load_done);
354 /* Switch page tables. */
355 @@ -89,6 +97,8 @@ process_exit (void)
356 struct thread *cur = thread_current ();
359 + printf ("%s: exit(%d)\n", cur->name, cur->exit_code);
361 /* Destroy the current process's page directory and switch back
362 to the kernel-only page directory. We have to set
363 cur->pagedir to NULL before switching page directories, or a
364 @@ -182,7 +192,7 @@ struct Elf32_Phdr
365 #define PF_R 4 /* Readable. */
367 static bool load_segment (struct file *, const struct Elf32_Phdr *);
368 -static bool setup_stack (void **esp);
369 +static bool setup_stack (const char *cmd_line, void **esp);
371 /* Aborts loading an executable, with an error message. */
372 #define LOAD_ERROR(MSG) \
373 @@ -198,13 +208,15 @@ static bool setup_stack (void **esp);
374 and its initial stack pointer into *ESP.
375 Returns true if successful, false otherwise. */
377 -load (const char *filename, void (**eip) (void), void **esp)
378 +load (const char *cmd_line, void (**eip) (void), void **esp)
380 struct thread *t = thread_current ();
381 + char filename[NAME_MAX + 2];
382 struct Elf32_Ehdr ehdr;
383 struct file *file = NULL;
385 bool success = false;
389 /* Allocate page directory. */
390 @@ -212,6 +224,14 @@ load (const char *filename, void (**eip)
391 if (t->pagedir == NULL)
392 LOAD_ERROR (("page directory allocation failed"));
394 + /* Extract filename from command line. */
395 + while (*cmd_line == ' ')
397 + strlcpy (filename, cmd_line, sizeof filename);
398 + cp = strchr (filename, ' ');
402 /* Open executable file. */
403 file = filesys_open (filename);
405 @@ -272,7 +292,7 @@ load (const char *filename, void (**eip)
409 - if (!setup_stack (esp))
410 + if (!setup_stack (cmd_line, esp))
414 @@ -381,10 +401,92 @@ load_segment (struct file *file, const s
418 -/* Create a minimal stack by mapping a zeroed page at the top of
419 - user virtual memory. */
420 +/* Reverse the order of the ARGC pointers to char in ARGV. */
422 +reverse (int argc, char **argv)
424 + for (; argc > 1; argc -= 2, argv++)
426 + char *tmp = argv[0];
427 + argv[0] = argv[argc - 1];
428 + argv[argc - 1] = tmp;
432 +/* Pushes the SIZE bytes in BUF onto the stack in KPAGE, whose
433 + page-relative stack pointer is *OFS, and then adjusts *OFS
434 + appropriately. The bytes pushed are rounded to a 32-bit
437 + If successful, returns a pointer to the newly pushed object.
438 + On failure, returns a null pointer. */
440 +push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size)
442 + size_t padsize = ROUND_UP (size, sizeof (uint32_t));
443 + if (*ofs < padsize)
447 + memcpy (kpage + *ofs + (padsize - size), buf, size);
448 + return kpage + *ofs + (padsize - size);
451 +/* Sets up command line arguments in KPAGE, which will be mapped
452 + to UPAGE in user space. The command line arguments are taken
453 + from CMD_LINE, separated by spaces. Sets *ESP to the initial
454 + stack pointer for the process. */
456 +init_cmd_line (uint8_t *kpage, uint8_t *upage, const char *cmd_line,
459 + size_t ofs = PGSIZE;
460 + char *const null = NULL;
461 + char *cmd_line_copy;
462 + char *karg, *saveptr;
466 + /* Push command line string. */
467 + cmd_line_copy = push (kpage, &ofs, cmd_line, strlen (cmd_line) + 1);
468 + if (cmd_line_copy == NULL)
471 + if (push (kpage, &ofs, &null, sizeof null) == NULL)
474 + /* Parse command line into arguments
475 + and push them in reverse order. */
477 + for (karg = strtok_r (cmd_line_copy, " ", &saveptr); karg != NULL;
478 + karg = strtok_r (NULL, " ", &saveptr))
480 + char *uarg = upage + (karg - (char *) kpage);
481 + if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
486 + /* Reverse the order of the command line arguments. */
487 + argv = (char **) (upage + ofs);
488 + reverse (argc, (char **) (kpage + ofs));
490 + /* Push argv, argc, "return address". */
491 + if (push (kpage, &ofs, &argv, sizeof argv) == NULL
492 + || push (kpage, &ofs, &argc, sizeof argc) == NULL
493 + || push (kpage, &ofs, &null, sizeof null) == NULL)
496 + /* Set initial stack pointer. */
497 + *esp = upage + ofs;
501 +/* Create a minimal stack for T by mapping a page at the
502 + top of user virtual memory. Fills in the page using CMD_LINE
503 + and sets *ESP to the stack pointer. */
505 -setup_stack (void **esp)
506 +setup_stack (const char *cmd_line, void **esp)
509 bool success = false;
510 @@ -392,9 +494,9 @@ setup_stack (void **esp)
511 kpage = palloc_get_page (PAL_USER | PAL_ZERO);
514 - success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
517 + uint8_t *upage = ((uint8_t *) PHYS_BASE) - PGSIZE;
518 + if (install_page (upage, kpage))
519 + success = init_cmd_line (kpage, upage, cmd_line, esp);
521 palloc_free_page (kpage);
523 Index: src/userprog/syscall.c
524 ===================================================================
525 RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/userprog/syscall.c,v
526 retrieving revision 1.4
527 diff -u -p -r1.4 syscall.c
528 --- src/userprog/syscall.c 26 Sep 2004 21:15:17 -0000 1.4
529 +++ src/userprog/syscall.c 1 Jan 2005 02:13:43 -0000
531 #include "userprog/syscall.h"
534 #include <syscall-nr.h>
535 +#include "userprog/process.h"
536 +#include "userprog/pagedir.h"
537 +#include "devices/kbd.h"
538 +#include "filesys/filesys.h"
539 +#include "filesys/file.h"
540 +#include "threads/init.h"
541 #include "threads/interrupt.h"
542 +#include "threads/malloc.h"
543 +#include "threads/mmu.h"
544 +#include "threads/palloc.h"
545 #include "threads/thread.h"
549 +static int sys_halt (void);
550 +static int sys_exit (int status);
551 +static int sys_exec (const char *ufile);
552 +static int sys_join (tid_t);
553 +static int sys_create (const char *ufile, unsigned initial_size);
554 +static int sys_remove (const char *ufile);
555 +static int sys_open (const char *ufile);
556 +static int sys_filesize (int handle);
557 +static int sys_read (int handle, void *udst_, unsigned size);
558 +static int sys_write (int handle, void *usrc_, unsigned size);
559 +static int sys_seek (int handle, unsigned position);
560 +static int sys_tell (int handle);
561 +static int sys_close (int handle);
563 static void syscall_handler (struct intr_frame *);
565 +static void copy_in (void *, const void *, size_t);
567 +static struct lock fs_lock;
572 intr_register (0x30, 3, INTR_ON, syscall_handler, "syscall");
573 + lock_init (&fs_lock, "fs");
576 +/* System call handler. */
578 +syscall_handler (struct intr_frame *f)
580 + typedef int syscall_function (int, int, int);
582 + /* A system call. */
585 + size_t arg_cnt; /* Number of arguments. */
586 + syscall_function *func; /* Implementation. */
589 + /* Table of system calls. */
590 + static const struct syscall syscall_table[] =
592 + {0, (syscall_function *) sys_halt},
593 + {1, (syscall_function *) sys_exit},
594 + {1, (syscall_function *) sys_exec},
595 + {1, (syscall_function *) sys_join},
596 + {2, (syscall_function *) sys_create},
597 + {1, (syscall_function *) sys_remove},
598 + {1, (syscall_function *) sys_open},
599 + {1, (syscall_function *) sys_filesize},
600 + {3, (syscall_function *) sys_read},
601 + {3, (syscall_function *) sys_write},
602 + {2, (syscall_function *) sys_seek},
603 + {1, (syscall_function *) sys_tell},
604 + {1, (syscall_function *) sys_close},
607 + struct syscall *sc;
611 + /* Get the system call. */
612 + copy_in (&call_nr, f->esp, sizeof call_nr);
613 + if (call_nr < 0 || call_nr >= sizeof syscall_table / sizeof *syscall_table)
615 + sc = syscall_table + call_nr;
617 + /* Get the system call arguments. */
618 + ASSERT (sc->arg_cnt <= sizeof args / sizeof *args);
619 + memset (args, 0, sizeof args);
620 + copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * sc->arg_cnt);
622 + /* Execute the system call,
623 + and set the return value. */
624 + f->eax = sc->func (args[0], args[1], args[2]);
627 +/* Returns true if UADDR is a valid, mapped user address,
628 + false otherwise. */
630 +verify_user (const void *uaddr)
632 + return pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL;
635 +/* Copies a byte from user address USRC to kernel address DST.
636 + USRC must be below PHYS_BASE.
637 + Returns true if successful, false if a segfault occurred. */
639 +get_user (uint8_t *dst, const uint8_t *usrc)
642 + asm ("mov %%eax, offset 1f; mov %%al, %2; mov %0, %%al; 1:"
643 + : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
647 +/* Writes BYTE to user address UDST.
648 + UDST must be below PHYS_BASE.
649 + Returns true if successful, false if a segfault occurred. */
651 +put_user (uint8_t *udst, uint8_t byte)
654 + asm ("mov %%eax, offset 1f; mov %0, %b2; 1:"
655 + : "=m" (*udst), "=&a" (eax) : "r" (byte));
659 +/* Copies SIZE bytes from user address USRC to kernel address
661 + Call thread_exit() if any of the user accesses are invalid. */
663 -syscall_handler (struct intr_frame *f UNUSED)
664 +copy_in (void *dst_, const void *usrc_, size_t size)
666 + uint8_t *dst = dst_;
667 + const uint8_t *usrc = usrc_;
669 + for (; size > 0; size--, dst++, usrc++)
670 + if (usrc >= (uint8_t *) PHYS_BASE || !get_user (dst, usrc))
674 +/* Creates a copy of user string US in kernel memory
675 + and returns it as a page that must be freed with
676 + palloc_free_page().
677 + Truncates the string at PGSIZE bytes in size.
678 + Call thread_exit() if any of the user accesses are invalid. */
680 +copy_in_string (const char *us)
685 + ks = palloc_get_page (0);
689 + for (length = 0; length < PGSIZE; length++)
691 + if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++))
694 + if (ks[length] == '\0')
697 + ks[PGSIZE - 1] = '\0';
701 +/* Halt system call. */
708 +/* Exit system call. */
710 +sys_exit (int exit_code)
712 + thread_current ()->exit_code = exit_code;
717 +/* Exec system call. */
719 +sys_exec (const char *ufile)
722 + char *kfile = copy_in_string (ufile);
724 + lock_acquire (&fs_lock);
725 + tid = process_execute (kfile);
726 + lock_release (&fs_lock);
728 + palloc_free_page (kfile);
733 +/* Join system call. */
735 +sys_join (tid_t child)
737 + return thread_join (child);
740 +/* Create system call. */
742 +sys_create (const char *ufile, unsigned initial_size)
744 + char *kfile = copy_in_string (ufile);
747 + lock_acquire (&fs_lock);
748 + ok = filesys_create (kfile, initial_size);
749 + lock_release (&fs_lock);
751 + palloc_free_page (kfile);
756 +/* Remove system call. */
758 +sys_remove (const char *ufile)
760 - printf ("system call!\n");
761 + char *kfile = copy_in_string (ufile);
764 + lock_acquire (&fs_lock);
765 + ok = filesys_remove (kfile);
766 + lock_release (&fs_lock);
768 + palloc_free_page (kfile);
773 +/* A file descriptor, for binding a file handle to a file. */
774 +struct file_descriptor
776 + list_elem elem; /* List element. */
777 + struct file *file; /* File. */
778 + int handle; /* File handle. */
781 +/* Open system call. */
783 +sys_open (const char *ufile)
785 + char *kfile = copy_in_string (ufile);
786 + struct file_descriptor *fd;
789 + fd = malloc (sizeof *fd);
792 + lock_acquire (&fs_lock);
793 + fd->file = filesys_open (kfile);
794 + if (fd->file != NULL)
796 + struct thread *cur = thread_current ();
797 + handle = fd->handle = cur->next_handle++;
798 + list_push_front (&cur->fds, &fd->elem);
802 + lock_release (&fs_lock);
805 + palloc_free_page (kfile);
809 +/* Returns the file descriptor associated with the given handle.
810 + Terminates the process if HANDLE is not associated with an
812 +static struct file_descriptor *
813 +lookup_fd (int handle)
815 + struct thread *cur = thread_current ();
818 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
821 + struct file_descriptor *fd;
822 + fd = list_entry (e, struct file_descriptor, elem);
823 + if (fd->handle == handle)
830 +/* Filesize system call. */
832 +sys_filesize (int handle)
834 + struct file_descriptor *fd = lookup_fd (handle);
837 + lock_acquire (&fs_lock);
838 + size = file_length (fd->file);
839 + lock_release (&fs_lock);
844 +/* Read system call. */
846 +sys_read (int handle, void *udst_, unsigned size)
848 + uint8_t *udst = udst_;
849 + struct file_descriptor *fd;
850 + int bytes_read = 0;
852 + /* Handle keyboard reads. */
853 + if (handle == STDIN_FILENO)
855 + for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
856 + if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, kbd_getc ()))
861 + /* Handle all other reads. */
862 + fd = lookup_fd (handle);
863 + lock_acquire (&fs_lock);
866 + /* How much to read into this page? */
867 + size_t page_left = PGSIZE - pg_ofs (udst);
868 + size_t read_amt = size < page_left ? size : page_left;
871 + /* Check that touching this page is okay. */
872 + if (!verify_user (udst))
874 + lock_release (&fs_lock);
878 + /* Read from file into page. */
879 + retval = file_read (fd->file, udst, read_amt);
882 + if (bytes_read == 0)
886 + bytes_read += retval;
888 + /* If it was a short read we're done. */
889 + if (retval != (off_t) read_amt)
896 + lock_release (&fs_lock);
901 +/* Write system call. */
903 +sys_write (int handle, void *usrc_, unsigned size)
905 + uint8_t *usrc = usrc_;
906 + struct file_descriptor *fd = NULL;
907 + int bytes_written = 0;
909 + /* Lookup up file descriptor. */
910 + if (handle != STDOUT_FILENO)
911 + fd = lookup_fd (handle);
913 + lock_acquire (&fs_lock);
916 + /* How much bytes to write to this page? */
917 + size_t page_left = PGSIZE - pg_ofs (usrc);
918 + size_t write_amt = size < page_left ? size : page_left;
921 + /* Check that we can touch this user page. */
922 + if (!verify_user (usrc))
924 + lock_release (&fs_lock);
928 + /* Do the write. */
929 + if (handle == STDOUT_FILENO)
931 + putbuf (usrc, write_amt);
932 + retval = write_amt;
935 + retval = file_write (fd->file, usrc, write_amt);
938 + if (bytes_written == 0)
939 + bytes_written = -1;
942 + bytes_written += retval;
944 + /* If it was a short write we're done. */
945 + if (retval != (off_t) write_amt)
952 + lock_release (&fs_lock);
954 + return bytes_written;
957 +/* Seek system call. */
959 +sys_seek (int handle, unsigned position)
961 + struct file_descriptor *fd = lookup_fd (handle);
963 + lock_acquire (&fs_lock);
964 + file_seek (fd->file, position);
965 + lock_release (&fs_lock);
970 +/* Tell system call. */
972 +sys_tell (int handle)
974 + struct file_descriptor *fd = lookup_fd (handle);
977 + lock_acquire (&fs_lock);
978 + position = file_tell (fd->file);
979 + lock_release (&fs_lock);
984 +/* Close system call. */
986 +sys_close (int handle)
988 + struct file_descriptor *fd = lookup_fd (handle);
989 + lock_acquire (&fs_lock);
990 + file_close (fd->file);
991 + lock_release (&fs_lock);
992 + list_remove (&fd->elem);
997 +/* On thread exit, close all open files. */
1001 + struct thread *cur = thread_current ();
1002 + list_elem *e, *next;
1004 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
1006 + struct file_descriptor *fd;
1007 + fd = list_entry (e, struct file_descriptor, elem);
1008 + next = list_next (e);
1009 + file_close (fd->file);
1013 Index: src/userprog/syscall.h
1014 ===================================================================
1015 RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/userprog/syscall.h,v
1016 retrieving revision 1.2
1017 diff -u -p -r1.2 syscall.h
1018 --- src/userprog/syscall.h 6 Sep 2004 05:38:45 -0000 1.2
1019 +++ src/userprog/syscall.h 1 Jan 2005 02:13:43 -0000
1021 #define USERPROG_SYSCALL_H
1023 void syscall_init (void);
1024 +void syscall_exit (void);
1026 #endif /* userprog/syscall.h */