1 diff -urpN pintos.orig/src/constants.h pintos/src/constants.h
2 --- pintos.orig/src/constants.h 2004-09-21 17:26:39.000000000 -0700
3 +++ pintos/src/constants.h 2004-09-27 16:41:17.000000000 -0700
5 /*#define MACRONAME 1 */
7 /* Uncomment if if you've implemented thread_join(). */
8 -/*#define THREAD_JOIN_IMPLEMENTED 1*/
9 +#define THREAD_JOIN_IMPLEMENTED 1
10 diff -urpN pintos.orig/src/threads/synch.c pintos/src/threads/synch.c
11 --- pintos.orig/src/threads/synch.c 2004-09-19 21:29:53.000000000 -0700
12 +++ pintos/src/threads/synch.c 2004-09-27 16:41:17.000000000 -0700
13 @@ -330,3 +330,35 @@ cond_name (const struct condition *cond)
19 +latch_init (struct latch *latch, const char *name)
21 + latch->released = false;
22 + lock_init (&latch->monitor_lock, name);
23 + cond_init (&latch->rel_cond, name);
27 +latch_acquire (struct latch *latch)
29 + lock_acquire (&latch->monitor_lock);
30 + if (!latch->released)
32 + cond_wait (&latch->rel_cond, &latch->monitor_lock);
33 + ASSERT (latch->released);
35 + lock_release (&latch->monitor_lock);
39 +latch_release (struct latch *latch)
41 + lock_acquire (&latch->monitor_lock);
42 + if (!latch->released)
44 + latch->released = true;
45 + cond_signal (&latch->rel_cond, &latch->monitor_lock);
47 + lock_release (&latch->monitor_lock);
49 diff -urpN pintos.orig/src/threads/synch.h pintos/src/threads/synch.h
50 --- pintos.orig/src/threads/synch.h 2004-09-19 21:29:53.000000000 -0700
51 +++ pintos/src/threads/synch.h 2004-09-27 16:41:17.000000000 -0700
52 @@ -44,4 +44,16 @@ void cond_signal (struct condition *, st
53 void cond_broadcast (struct condition *, struct lock *);
54 const char *cond_name (const struct condition *);
59 + bool released; /* Released yet? */
60 + struct lock monitor_lock; /* Monitor lock. */
61 + struct condition rel_cond; /* Signaled when released. */
64 +void latch_init (struct latch *, const char *);
65 +void latch_acquire (struct latch *);
66 +void latch_release (struct latch *);
68 #endif /* threads/synch.h */
69 diff -urpN pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
70 --- pintos.orig/src/threads/thread.c 2004-09-26 14:15:17.000000000 -0700
71 +++ pintos/src/threads/thread.c 2004-09-27 16:41:17.000000000 -0700
73 #include "threads/synch.h"
75 #include "userprog/process.h"
76 +#include "userprog/syscall.h"
79 /* Random value for struct thread's `magic' member.
80 @@ -80,6 +81,7 @@ thread_init (void)
81 init_thread (initial_thread, "main", PRI_DEFAULT);
82 initial_thread->status = THREAD_RUNNING;
83 initial_thread->tid = allocate_tid ();
84 + sema_up (&initial_thread->can_die);
87 /* Starts preemptive thread scheduling by enabling interrupts.
88 @@ -148,6 +150,7 @@ thread_create (const char *name, int pri
89 /* Initialize thread. */
90 init_thread (t, name, priority);
91 tid = t->tid = allocate_tid ();
92 + list_push_back (&thread_current ()->children, &t->children_elem);
94 /* Stack frame for kernel_thread(). */
95 kf = alloc_frame (t, sizeof *kf);
96 @@ -224,16 +227,36 @@ thread_tid (void)
100 + struct thread *t = thread_current ();
101 + list_elem *e, *next;
103 ASSERT (!intr_context ());
110 + /* Notify our parent that we're dying. */
111 + latch_release (&t->ready_to_die);
113 + /* Notify our children that they can die. */
114 + for (e = list_begin (&t->children); e != list_end (&t->children);
117 + struct thread *child = list_entry (e, struct thread, children_elem);
118 + next = list_next (e);
120 + sema_up (&child->can_die);
123 + /* Wait until our parent is ready for us to die. */
124 + sema_down (&t->can_die);
126 /* Just set our status to dying and schedule another process.
127 We will be destroyed during the call to schedule_tail(). */
129 - thread_current ()->status = THREAD_DYING;
130 + t->status = THREAD_DYING;
134 @@ -270,6 +293,26 @@ thread_block (void)
135 thread_current ()->status = THREAD_BLOCKED;
139 +/* Waits for thread with tid CHILD_TID to die. */
141 +thread_join (tid_t child_tid)
143 + struct thread *cur = thread_current ();
146 + for (e = list_begin (&cur->children); e != list_end (&cur->children); )
148 + struct thread *child = list_entry (e, struct thread, children_elem);
150 + if (child->tid == child_tid)
152 + latch_acquire (&child->ready_to_die);
153 + return child->ret_code;
159 /* Idle thread. Executes when no other thread is ready to run. */
161 @@ -335,6 +378,12 @@ init_thread (struct thread *t, const cha
162 strlcpy (t->name, name, sizeof t->name);
163 t->stack = (uint8_t *) t + PGSIZE;
164 t->priority = priority;
165 + latch_init (&t->ready_to_die, "ready-to-die");
166 + sema_init (&t->can_die, 0, "can-die");
167 + list_init (&t->children);
169 + list_init (&t->fds);
170 + t->next_handle = 2;
171 t->magic = THREAD_MAGIC;
174 diff -urpN pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
175 --- pintos.orig/src/threads/thread.h 2004-09-26 14:15:17.000000000 -0700
176 +++ pintos/src/threads/thread.h 2004-09-27 16:41:17.000000000 -0700
181 +#include "threads/synch.h"
183 /* States in a thread's life cycle. */
185 @@ -89,12 +90,23 @@ struct thread
186 uint8_t *stack; /* Saved stack pointer. */
187 int priority; /* Priority. */
189 + /* Members for implementing thread_join(). */
190 + struct latch ready_to_die; /* Release when thread about to die. */
191 + struct semaphore can_die; /* Up when thread allowed to die. */
192 + struct list children; /* List of child threads. */
193 + list_elem children_elem; /* Element of `children' list. */
194 + int ret_code; /* Return status. */
196 /* Shared between thread.c and synch.c. */
197 list_elem elem; /* List element. */
200 /* Owned by userprog/process.c. */
201 uint32_t *pagedir; /* Page directory. */
203 + /* Owned by syscall.c. */
204 + struct list fds; /* List of file descriptors. */
205 + int next_handle; /* Next handle value. */
208 /* Owned by thread.c */
209 @@ -119,7 +131,7 @@ void thread_yield (void);
210 void thread_block (void);
212 /* This function will be implemented in problem 1-2. */
213 -void thread_join (tid_t);
214 +int thread_join (tid_t);
216 /* These functions will be implemented in problem 1-3. */
217 void thread_set_priority (int);
218 diff -urpN pintos.orig/src/userprog/exception.c pintos/src/userprog/exception.c
219 --- pintos.orig/src/userprog/exception.c 2004-09-26 14:15:17.000000000 -0700
220 +++ pintos/src/userprog/exception.c 2004-09-27 16:41:17.000000000 -0700
221 @@ -147,6 +147,13 @@ page_fault (struct intr_frame *f)
222 write = (f->error_code & PF_W) != 0;
223 user = (f->error_code & PF_U) != 0;
227 + f->eip = (void (*) (void)) f->eax;
232 /* To implement virtual memory, delete the rest of the function
233 body, and replace it with code that brings in the page to
234 which fault_addr refers. */
235 diff -urpN pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
236 --- pintos.orig/src/userprog/process.c 2004-09-22 17:58:29.000000000 -0700
237 +++ pintos/src/userprog/process.c 2004-09-27 16:41:17.000000000 -0700
238 @@ -182,7 +182,7 @@ struct Elf32_Phdr
239 #define PF_R 4 /* Readable. */
241 static bool load_segment (struct file *, const struct Elf32_Phdr *);
242 -static bool setup_stack (void **esp);
243 +static bool setup_stack (const char *cmdline, void **esp);
245 /* Aborts loading an executable, with an error message. */
246 #define LOAD_ERROR(MSG) \
247 @@ -198,13 +198,15 @@ static bool setup_stack (void **esp);
248 and its initial stack pointer into *ESP.
249 Returns true if successful, false otherwise. */
251 -load (const char *filename, void (**eip) (void), void **esp)
252 +load (const char *cmdline, void (**eip) (void), void **esp)
254 struct thread *t = thread_current ();
255 + char filename[NAME_MAX + 2];
256 struct Elf32_Ehdr ehdr;
257 struct file *file = NULL;
259 bool success = false;
263 /* Allocate page directory. */
264 @@ -212,6 +214,14 @@ load (const char *filename, void (**eip)
265 if (t->pagedir == NULL)
266 LOAD_ERROR (("page directory allocation failed"));
268 + /* Extract filename from command line. */
269 + while (*cmdline == ' ')
271 + strlcpy (filename, cmdline, sizeof filename);
272 + cp = strchr (filename, ' ');
276 /* Open executable file. */
277 file = filesys_open (filename);
279 @@ -269,7 +279,7 @@ load (const char *filename, void (**eip)
283 - if (!setup_stack (esp))
284 + if (!setup_stack (cmdline, esp))
288 @@ -371,10 +381,80 @@ load_segment (struct file *file, const s
292 -/* Create a minimal stack by mapping a zeroed page at the top of
293 - user virtual memory. */
295 +reverse (int argc, char **argv)
297 + for (; argc > 1; argc -= 2, argv++)
299 + char *tmp = argv[0];
300 + argv[0] = argv[argc - 1];
301 + argv[argc - 1] = tmp;
306 +push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size)
308 + size_t padsize = ROUND_UP (size, sizeof (uint32_t));
309 + if (*ofs < padsize)
313 + memcpy (kpage + *ofs + (padsize - size), buf, size);
314 + return kpage + *ofs + (padsize - size);
318 +init_cmdline (uint8_t *kpage, uint8_t *upage, const char *cmdline,
321 + size_t ofs = PGSIZE;
322 + char *const null = NULL;
323 + char *cmdline_copy;
324 + char *karg, *saveptr;
328 + /* Push command line string. */
329 + cmdline_copy = push (kpage, &ofs, cmdline, strlen (cmdline) + 1);
330 + if (cmdline_copy == NULL)
333 + if (push (kpage, &ofs, &null, sizeof null) == NULL)
336 + /* Parse command line into arguments
337 + and push them in reverse order. */
339 + for (karg = strtok_r (cmdline_copy, " ", &saveptr); karg != NULL;
340 + karg = strtok_r (NULL, " ", &saveptr))
342 + char *uarg = upage + (karg - (char *) kpage);
343 + if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
348 + /* Reverse the order of the command line arguments. */
349 + argv = (char **) (upage + ofs);
350 + reverse (argc, (char **) (kpage + ofs));
352 + /* Push argv, argc, "return address". */
353 + if (push (kpage, &ofs, &argv, sizeof argv) == NULL
354 + || push (kpage, &ofs, &argc, sizeof argc) == NULL
355 + || push (kpage, &ofs, &null, sizeof null) == NULL)
358 + /* Set initial stack pointer. */
359 + *esp = upage + ofs;
363 +/* Create a minimal stack for T by mapping a page at the
364 + top of user virtual memory. Fills in the page using CMDLINE
365 + and sets *ESP to the stack pointer. */
367 -setup_stack (void **esp)
368 +setup_stack (const char *cmdline, void **esp)
371 bool success = false;
372 @@ -382,9 +462,9 @@ setup_stack (void **esp)
373 kpage = palloc_get_page (PAL_USER | PAL_ZERO);
376 - success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
379 + uint8_t *upage = ((uint8_t *) PHYS_BASE) - PGSIZE;
380 + if (install_page (upage, kpage))
381 + success = init_cmdline (kpage, upage, cmdline, esp);
383 palloc_free_page (kpage);
385 diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
386 --- pintos.orig/src/userprog/syscall.c 2004-09-26 14:15:17.000000000 -0700
387 +++ pintos/src/userprog/syscall.c 2004-09-27 16:43:00.000000000 -0700
389 #include "userprog/syscall.h"
392 #include <syscall-nr.h>
393 +#include "userprog/process.h"
394 +#include "userprog/pagedir.h"
395 +#include "devices/kbd.h"
396 +#include "filesys/filesys.h"
397 +#include "filesys/file.h"
398 +#include "threads/init.h"
399 #include "threads/interrupt.h"
400 +#include "threads/malloc.h"
401 +#include "threads/mmu.h"
402 +#include "threads/palloc.h"
403 #include "threads/thread.h"
406 +typedef int syscall_function (int, int, int);
408 +static int sys_halt (void);
409 +static int sys_exit (int status);
410 +static int sys_exec (const char *ufile);
411 +static int sys_join (tid_t);
412 +static int sys_create (const char *ufile, unsigned initial_size);
413 +static int sys_remove (const char *ufile);
414 +static int sys_open (const char *ufile);
415 +static int sys_filesize (int handle);
416 +static int sys_read (int handle, void *udst_, unsigned size);
417 +static int sys_write (int handle, void *usrc_, unsigned size);
418 +static int sys_seek (int handle, unsigned position);
419 +static int sys_tell (int handle);
420 +static int sys_close (int handle);
425 + syscall_function *func;
428 +struct syscall syscall_table[] =
430 + {0, (syscall_function *) sys_halt},
431 + {1, (syscall_function *) sys_exit},
432 + {1, (syscall_function *) sys_exec},
433 + {1, (syscall_function *) sys_join},
434 + {2, (syscall_function *) sys_create},
435 + {1, (syscall_function *) sys_remove},
436 + {1, (syscall_function *) sys_open},
437 + {1, (syscall_function *) sys_filesize},
438 + {3, (syscall_function *) sys_read},
439 + {3, (syscall_function *) sys_write},
440 + {2, (syscall_function *) sys_seek},
441 + {1, (syscall_function *) sys_tell},
442 + {1, (syscall_function *) sys_close},
444 +static const int syscall_cnt = sizeof syscall_table / sizeof *syscall_table;
446 static void syscall_handler (struct intr_frame *);
448 +static void copy_in (void *, const void *, size_t);
450 +static struct lock fs_lock;
455 intr_register (0x30, 3, INTR_ON, syscall_handler, "syscall");
456 + lock_init (&fs_lock, "fs");
461 -syscall_handler (struct intr_frame *f UNUSED)
462 +syscall_handler (struct intr_frame *f)
464 - printf ("system call!\n");
469 + copy_in (&call_nr, f->esp, sizeof call_nr);
470 + if (call_nr < 0 || call_nr >= syscall_cnt)
472 + printf ("bad syscall number %d\n", call_nr);
476 + s = syscall_table + call_nr;
477 + ASSERT (s->arg_cnt <= sizeof args / sizeof *args);
478 + memset (args, 0, sizeof args);
479 + copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * s->arg_cnt);
480 + f->eax = s->func (args[0], args[1], args[2]);
484 +verify_user (const void *uaddr)
486 + return pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL;
489 +static inline bool get_user (uint8_t *dst, const uint8_t *usrc) {
491 + asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
492 + : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
496 +static inline bool put_user (uint8_t *udst, uint8_t byte) {
498 + asm ("movl $1f, %%eax; movb %b2, %0; 1:"
499 + : "=m" (*udst), "=&a" (eax) : "r" (byte));
504 +copy_in (void *dst_, const void *usrc_, size_t size)
506 + uint8_t *dst = dst_;
507 + const uint8_t *usrc = usrc_;
509 + for (; size > 0; size--, dst++, usrc++)
510 + if (usrc >= (uint8_t *) PHYS_BASE || !get_user (dst, usrc))
515 +copy_in_string (const char *us)
520 + ks = palloc_get_page (0);
523 + printf ("copy_in_string: out of memory\n");
527 + for (length = 0; length < PGSIZE; length++)
529 + if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++))
531 + printf ("bad user reference (%p)\n", us + length);
535 + if (ks[length] == '\0')
539 + printf ("copy_in_string: string too long\n");
540 + palloc_free_page (ks);
551 +sys_exit (int ret_code)
553 + thread_current ()->ret_code = ret_code;
559 +sys_exec (const char *ufile)
562 + char *kfile = copy_in_string (ufile);
564 + lock_acquire (&fs_lock);
565 + tid = process_execute (kfile);
566 + lock_release (&fs_lock);
568 + palloc_free_page (kfile);
574 +sys_join (tid_t child)
576 + return thread_join (child);
580 +sys_create (const char *ufile, unsigned initial_size)
582 + char *kfile = copy_in_string (ufile);
585 + lock_acquire (&fs_lock);
586 + ok = filesys_create (kfile, initial_size);
587 + lock_release (&fs_lock);
589 + palloc_free_page (kfile);
595 +sys_remove (const char *ufile)
597 + char *kfile = copy_in_string (ufile);
600 + lock_acquire (&fs_lock);
601 + ok = filesys_remove (kfile);
602 + lock_release (&fs_lock);
604 + palloc_free_page (kfile);
617 +sys_open (const char *ufile)
619 + char *kfile = copy_in_string (ufile);
623 + fd = malloc (sizeof *fd);
627 + lock_acquire (&fs_lock);
628 + fd->file = filesys_open (kfile);
629 + if (fd->file != NULL)
631 + struct thread *cur = thread_current ();
632 + handle = fd->handle = cur->next_handle++;
633 + list_push_front (&cur->fds, &fd->elem);
637 + lock_release (&fs_lock);
640 + palloc_free_page (kfile);
644 +static struct fildes *
645 +lookup_fd (int handle)
647 + struct thread *cur = thread_current ();
650 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
653 + struct fildes *fd = list_entry (e, struct fildes, elem);
654 + if (fd->handle == handle)
658 + printf ("no handle %d\n", handle);
663 +sys_filesize (int handle)
665 + struct fildes *fd = lookup_fd (handle);
668 + lock_acquire (&fs_lock);
669 + size = file_length (fd->file);
670 + lock_release (&fs_lock);
676 +sys_read (int handle, void *udst_, unsigned size)
678 + uint8_t *udst = udst_;
680 + int bytes_read = 0;
682 + if (handle == STDIN_FILENO)
684 + for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
685 + if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, kbd_getc ()))
690 + lock_acquire (&fs_lock);
691 + fd = lookup_fd (handle);
694 + size_t page_left = PGSIZE - pg_ofs (udst);
695 + size_t read_amt = size < page_left ? size : page_left;
698 + if (!verify_user (udst))
700 + lock_release (&fs_lock);
704 + retval = file_read (fd->file, udst, read_amt);
707 + if (bytes_read == 0)
712 + bytes_read += retval;
713 + if (retval != (off_t) read_amt)
719 + lock_release (&fs_lock);
725 +sys_write (int handle, void *usrc_, unsigned size)
727 + uint8_t *usrc = usrc_;
728 + struct fildes *fd = NULL;
729 + int bytes_written = 0;
731 + lock_acquire (&fs_lock);
732 + if (handle != STDOUT_FILENO)
733 + fd = lookup_fd (handle);
736 + size_t page_left = PGSIZE - pg_ofs (usrc);
737 + size_t write_amt = size < page_left ? size : page_left;
740 + if (!verify_user (usrc))
742 + lock_release (&fs_lock);
746 + if (handle == STDOUT_FILENO)
748 + putbuf (usrc, write_amt);
749 + retval = write_amt;
752 + retval = file_write (fd->file, usrc, write_amt);
755 + if (bytes_written == 0)
756 + bytes_written = -1;
760 + bytes_written += retval;
761 + if (retval != (off_t) write_amt)
767 + lock_release (&fs_lock);
769 + return bytes_written;
773 +sys_seek (int handle, unsigned position)
775 + struct fildes *fd = lookup_fd (handle);
777 + lock_acquire (&fs_lock);
778 + file_seek (fd->file, position);
779 + lock_release (&fs_lock);
785 +sys_tell (int handle)
787 + struct fildes *fd = lookup_fd (handle);
790 + lock_acquire (&fs_lock);
791 + position = file_tell (fd->file);
792 + lock_release (&fs_lock);
798 +sys_close (int handle)
800 + struct fildes *fd = lookup_fd (handle);
801 + lock_acquire (&fs_lock);
802 + file_close (fd->file);
803 + lock_release (&fs_lock);
804 + list_remove (&fd->elem);
812 + struct thread *cur = thread_current ();
813 + list_elem *e, *next;
815 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
817 + struct fildes *fd = list_entry (e, struct fildes, elem);
818 + next = list_next (e);
819 + file_close (fd->file);
823 diff -urpN pintos.orig/src/userprog/syscall.h pintos/src/userprog/syscall.h
824 --- pintos.orig/src/userprog/syscall.h 2004-09-05 22:38:45.000000000 -0700
825 +++ pintos/src/userprog/syscall.h 2004-09-27 16:41:17.000000000 -0700
827 #define USERPROG_SYSCALL_H
829 void syscall_init (void);
830 +void syscall_exit (void);
832 #endif /* userprog/syscall.h */