1 diff -urp 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-22 00:34:01.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 Only in pintos/src: constants.h~
11 diff -urp pintos.orig/src/threads/synch.c pintos/src/threads/synch.c
12 --- pintos.orig/src/threads/synch.c 2004-09-19 21:29:53.000000000 -0700
13 +++ pintos/src/threads/synch.c 2004-09-22 00:30:05.000000000 -0700
14 @@ -330,3 +330,35 @@ cond_name (const struct condition *cond)
20 +latch_init (struct latch *latch, const char *name)
22 + latch->released = false;
23 + lock_init (&latch->monitor_lock, name);
24 + cond_init (&latch->rel_cond, name);
28 +latch_acquire (struct latch *latch)
30 + lock_acquire (&latch->monitor_lock);
31 + if (!latch->released)
33 + cond_wait (&latch->rel_cond, &latch->monitor_lock);
34 + ASSERT (latch->released);
36 + lock_release (&latch->monitor_lock);
40 +latch_release (struct latch *latch)
42 + lock_acquire (&latch->monitor_lock);
43 + if (!latch->released)
45 + latch->released = true;
46 + cond_signal (&latch->rel_cond, &latch->monitor_lock);
48 + lock_release (&latch->monitor_lock);
50 diff -urp pintos.orig/src/threads/synch.h pintos/src/threads/synch.h
51 --- pintos.orig/src/threads/synch.h 2004-09-19 21:29:53.000000000 -0700
52 +++ pintos/src/threads/synch.h 2004-09-22 00:30:05.000000000 -0700
53 @@ -44,4 +44,16 @@ void cond_signal (struct condition *, st
54 void cond_broadcast (struct condition *, struct lock *);
55 const char *cond_name (const struct condition *);
60 + bool released; /* Released yet? */
61 + struct lock monitor_lock; /* Monitor lock. */
62 + struct condition rel_cond; /* Signaled when released. */
65 +void latch_init (struct latch *, const char *);
66 +void latch_acquire (struct latch *);
67 +void latch_release (struct latch *);
69 #endif /* threads/synch.h */
70 diff -urp pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
71 --- pintos.orig/src/threads/thread.c 2004-09-21 22:42:17.000000000 -0700
72 +++ pintos/src/threads/thread.c 2004-09-22 00:32:39.000000000 -0700
74 #include "threads/synch.h"
76 #include "userprog/process.h"
77 +#include "userprog/syscall.h"
80 /* Random value for struct thread's `magic' member.
81 @@ -75,6 +76,7 @@ thread_init (void)
82 init_thread (initial_thread, "main", PRI_DEFAULT);
83 initial_thread->status = THREAD_RUNNING;
84 initial_thread->tid = allocate_tid ();
85 + sema_up (&initial_thread->can_die);
88 /* Starts preemptive thread scheduling by enabling interrupts.
89 @@ -119,6 +121,7 @@ thread_create (const char *name, int pri
90 /* Initialize thread. */
91 init_thread (t, name, priority);
92 tid = t->tid = allocate_tid ();
93 + list_push_back (&thread_current ()->children, &t->children_elem);
95 /* Stack frame for kernel_thread(). */
96 kf = alloc_frame (t, sizeof *kf);
97 @@ -195,16 +198,36 @@ thread_tid (void)
101 + struct thread *t = thread_current ();
102 + list_elem *e, *next;
104 ASSERT (!intr_context ());
111 + /* Notify our parent that we're dying. */
112 + latch_release (&t->ready_to_die);
114 + /* Notify our children that they can die. */
115 + for (e = list_begin (&t->children); e != list_end (&t->children);
118 + struct thread *child = list_entry (e, struct thread, children_elem);
119 + next = list_next (e);
121 + sema_up (&child->can_die);
124 + /* Wait until our parent is ready for us to die. */
125 + sema_down (&t->can_die);
127 /* Just set our status to dying and schedule another process.
128 We will be destroyed during the call to schedule_tail(). */
130 - thread_current ()->status = THREAD_DYING;
131 + t->status = THREAD_DYING;
135 @@ -241,6 +264,26 @@ thread_block (void)
136 thread_current ()->status = THREAD_BLOCKED;
140 +/* Waits for thread with tid CHILD_TID to die. */
142 +thread_join (tid_t child_tid)
144 + struct thread *cur = thread_current ();
147 + for (e = list_begin (&cur->children); e != list_end (&cur->children); )
149 + struct thread *child = list_entry (e, struct thread, children_elem);
151 + if (child->tid == child_tid)
153 + latch_acquire (&child->ready_to_die);
154 + return child->ret_code;
160 /* Idle thread. Executes when no other thread is ready to run. */
162 @@ -306,6 +349,12 @@ init_thread (struct thread *t, const cha
163 strlcpy (t->name, name, sizeof t->name);
164 t->stack = (uint8_t *) t + PGSIZE;
165 t->priority = priority;
166 + latch_init (&t->ready_to_die, "ready-to-die");
167 + sema_init (&t->can_die, 0, "can-die");
168 + list_init (&t->children);
170 + list_init (&t->fds);
171 + t->next_handle = 2;
172 t->magic = THREAD_MAGIC;
175 Only in pintos/src/threads: thread.c.orig
176 Only in pintos/src/threads: thread.c.rej
177 Only in pintos/src/threads: thread.c~
178 diff -urp pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
179 --- pintos.orig/src/threads/thread.h 2004-09-20 15:29:18.000000000 -0700
180 +++ pintos/src/threads/thread.h 2004-09-22 00:30:05.000000000 -0700
185 +#include "threads/synch.h"
187 /* States in a thread's life cycle. */
189 @@ -89,12 +90,23 @@ struct thread
190 uint8_t *stack; /* Saved stack pointer. */
191 int priority; /* Priority. */
193 + /* Members for implementing thread_join(). */
194 + struct latch ready_to_die; /* Release when thread about to die. */
195 + struct semaphore can_die; /* Up when thread allowed to die. */
196 + struct list children; /* List of child threads. */
197 + list_elem children_elem; /* Element of `children' list. */
198 + int ret_code; /* Return status. */
200 /* Shared between thread.c and synch.c. */
201 list_elem elem; /* List element. */
204 /* Owned by userprog/process.c. */
205 uint32_t *pagedir; /* Page directory. */
207 + /* Owned by syscall.c. */
208 + struct list fds; /* List of file descriptors. */
209 + int next_handle; /* Next handle value. */
212 /* Owned by thread.c */
213 @@ -117,7 +129,7 @@ void thread_yield (void);
214 void thread_block (void);
216 /* This function will be implemented in problem 1-2. */
217 -void thread_join (tid_t);
218 +int thread_join (tid_t);
220 /* These functions will be implemented in problem 1-3. */
221 void thread_set_priority (int);
222 Only in pintos/src/userprog: build
223 diff -urp pintos.orig/src/userprog/exception.c pintos/src/userprog/exception.c
224 --- pintos.orig/src/userprog/exception.c 2004-09-20 12:06:58.000000000 -0700
225 +++ pintos/src/userprog/exception.c 2004-09-22 00:30:05.000000000 -0700
226 @@ -134,6 +134,13 @@ page_fault (struct intr_frame *f)
227 write = (f->error_code & PF_W) != 0;
228 user = (f->error_code & PF_U) != 0;
232 + f->eip = (void (*) (void)) f->eax;
237 /* To implement virtual memory, delete the rest of the function
238 body, and replace it with code that brings in the page to
239 which fault_addr refers. */
240 diff -urp pintos.orig/src/userprog/pagedir.c pintos/src/userprog/pagedir.c
241 --- pintos.orig/src/userprog/pagedir.c 2004-09-21 22:42:17.000000000 -0700
242 +++ pintos/src/userprog/pagedir.c 2004-09-22 00:32:23.000000000 -0700
243 @@ -99,7 +99,7 @@ pagedir_set_page (uint32_t *pd, void *up
244 ASSERT (pg_ofs (upage) == 0);
245 ASSERT (pg_ofs (kpage) == 0);
246 ASSERT (upage < PHYS_BASE);
247 - ASSERT (lookup_page (pd, upage, false) == NULL);
248 + ASSERT (pagedir_get_page (pd, upage) == NULL);
250 pte = lookup_page (pd, upage, true);
252 Only in pintos/src/userprog: pagedir.c.orig
253 Only in pintos/src/userprog: pagedir.c.rej
254 Only in pintos/src/userprog: pagedir.c.rej~
255 Only in pintos/src/userprog: pagedir.c~
256 diff -urp pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
257 --- pintos.orig/src/userprog/process.c 2004-09-21 22:42:17.000000000 -0700
258 +++ pintos/src/userprog/process.c 2004-09-22 00:30:05.000000000 -0700
259 @@ -182,7 +182,7 @@ struct Elf32_Phdr
260 #define PF_R 4 /* Readable. */
262 static bool load_segment (struct file *, const struct Elf32_Phdr *);
263 -static bool setup_stack (void **esp);
264 +static bool setup_stack (const char *cmdline, void **esp);
266 /* Aborts loading an executable, with an error message. */
267 #define LOAD_ERROR(MSG) \
268 @@ -198,13 +198,15 @@ static bool setup_stack (void **esp);
269 and its initial stack pointer into *ESP.
270 Returns true if successful, false otherwise. */
272 -load (const char *filename, void (**eip) (void), void **esp)
273 +load (const char *cmdline, void (**eip) (void), void **esp)
275 struct thread *t = thread_current ();
276 + char filename[NAME_MAX + 2];
277 struct Elf32_Ehdr ehdr;
278 struct file *file = NULL;
280 bool success = false;
284 /* Allocate page directory. */
285 @@ -212,6 +214,14 @@ load (const char *filename, void (**eip)
286 if (t->pagedir == NULL)
287 LOAD_ERROR (("page directory allocation failed"));
289 + /* Extract filename from command line. */
290 + while (*cmdline == ' ')
292 + strlcpy (filename, cmdline, sizeof filename);
293 + cp = strchr (filename, ' ');
297 /* Open executable file. */
298 file = filesys_open (filename);
300 @@ -269,7 +279,7 @@ load (const char *filename, void (**eip)
304 - if (!setup_stack (esp))
305 + if (!setup_stack (cmdline, esp))
309 @@ -371,10 +381,80 @@ load_segment (struct file *file, const s
313 -/* Create a minimal stack by mapping a zeroed page at the top of
314 - user virtual memory. */
316 +reverse (int argc, char **argv)
318 + for (; argc > 1; argc -= 2, argv++)
320 + char *tmp = argv[0];
321 + argv[0] = argv[argc - 1];
322 + argv[argc - 1] = tmp;
327 +push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size)
329 + size_t padsize = ROUND_UP (size, sizeof (uint32_t));
330 + if (*ofs < padsize)
334 + memcpy (kpage + *ofs + (padsize - size), buf, size);
335 + return kpage + *ofs + (padsize - size);
339 +init_cmdline (uint8_t *kpage, uint8_t *upage, const char *cmdline,
342 + size_t ofs = PGSIZE;
343 + char *const null = NULL;
344 + char *cmdline_copy;
345 + char *karg, *saveptr;
349 + /* Push command line string. */
350 + cmdline_copy = push (kpage, &ofs, cmdline, strlen (cmdline) + 1);
351 + if (cmdline_copy == NULL)
354 + if (push (kpage, &ofs, &null, sizeof null) == NULL)
357 + /* Parse command line into arguments
358 + and push them in reverse order. */
360 + for (karg = strtok_r (cmdline_copy, " ", &saveptr); karg != NULL;
361 + karg = strtok_r (NULL, " ", &saveptr))
363 + char *uarg = upage + (karg - (char *) kpage);
364 + if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
369 + /* Reverse the order of the command line arguments. */
370 + argv = (char **) (upage + ofs);
371 + reverse (argc, (char **) (kpage + ofs));
373 + /* Push argv, argc, "return address". */
374 + if (push (kpage, &ofs, &argv, sizeof argv) == NULL
375 + || push (kpage, &ofs, &argc, sizeof argc) == NULL
376 + || push (kpage, &ofs, &null, sizeof null) == NULL)
379 + /* Set initial stack pointer. */
380 + *esp = upage + ofs;
384 +/* Create a minimal stack for T by mapping a page at the
385 + top of user virtual memory. Fills in the page using CMDLINE
386 + and sets *ESP to the stack pointer. */
388 -setup_stack (void **esp)
389 +setup_stack (const char *cmdline, void **esp)
392 bool success = false;
393 @@ -382,9 +462,9 @@ setup_stack (void **esp)
394 kpage = palloc_get (PAL_USER | PAL_ZERO);
397 - success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
400 + uint8_t *upage = ((uint8_t *) PHYS_BASE) - PGSIZE;
401 + if (install_page (upage, kpage))
402 + success = init_cmdline (kpage, upage, cmdline, esp);
406 Only in pintos/src/userprog: process.c.orig
407 diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
408 --- pintos.orig/src/userprog/syscall.c 2004-09-05 22:19:19.000000000 -0700
409 +++ pintos/src/userprog/syscall.c 2004-09-22 00:30:05.000000000 -0700
411 #include "userprog/syscall.h"
414 #include <syscall-nr.h>
415 +#include "userprog/process.h"
416 +#include "userprog/pagedir.h"
417 +#include "devices/kbd.h"
418 +#include "filesys/filesys.h"
419 +#include "filesys/file.h"
420 +#include "threads/init.h"
421 #include "threads/interrupt.h"
422 +#include "threads/malloc.h"
423 +#include "threads/mmu.h"
424 +#include "threads/palloc.h"
425 #include "threads/thread.h"
427 +typedef int syscall_function (int, int, int);
429 +static int sys_halt (void);
430 +static int sys_exit (int status);
431 +static int sys_exec (const char *ufile);
432 +static int sys_join (tid_t);
433 +static int sys_create (const char *ufile, unsigned initial_size);
434 +static int sys_remove (const char *ufile);
435 +static int sys_open (const char *ufile);
436 +static int sys_filesize (int handle);
437 +static int sys_read (int handle, void *udst_, unsigned size);
438 +static int sys_write (int handle, void *usrc_, unsigned size);
439 +static int sys_seek (int handle, unsigned position);
440 +static int sys_tell (int handle);
441 +static int sys_close (int handle);
446 + syscall_function *func;
449 +struct syscall syscall_table[] =
451 + {0, (syscall_function *) sys_halt},
452 + {1, (syscall_function *) sys_exit},
453 + {1, (syscall_function *) sys_exec},
454 + {1, (syscall_function *) sys_join},
455 + {2, (syscall_function *) sys_create},
456 + {1, (syscall_function *) sys_remove},
457 + {1, (syscall_function *) sys_open},
458 + {1, (syscall_function *) sys_filesize},
459 + {3, (syscall_function *) sys_read},
460 + {3, (syscall_function *) sys_write},
461 + {2, (syscall_function *) sys_seek},
462 + {1, (syscall_function *) sys_tell},
463 + {1, (syscall_function *) sys_close},
465 +static const int syscall_cnt = sizeof syscall_table / sizeof *syscall_table;
467 static void syscall_handler (struct intr_frame *);
468 +static void copy_in (void *, const void *, size_t);
470 +static struct lock fs_lock;
475 intr_register (0x30, 3, INTR_ON, syscall_handler, "syscall");
476 + lock_init (&fs_lock, "fs");
480 syscall_handler (struct intr_frame *f)
482 - printf ("system call!\n");
487 + copy_in (&call_nr, f->esp, sizeof call_nr);
488 + if (call_nr < 0 || call_nr >= syscall_cnt)
490 + printf ("bad syscall number %d\n", call_nr);
494 + s = syscall_table + call_nr;
495 + ASSERT (s->arg_cnt <= sizeof args / sizeof *args);
496 + memset (args, 0, sizeof args);
497 + copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * s->arg_cnt);
498 + f->eax = s->func (args[0], args[1], args[2]);
502 +verify_user (const void *uaddr)
504 + return pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL;
507 +static inline bool get_user (uint8_t *dst, const uint8_t *usrc) {
509 + asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
510 + : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
514 +static inline bool put_user (uint8_t *udst, uint8_t byte) {
516 + asm ("movl $1f, %%eax; movb %b2, %0; 1:"
517 + : "=m" (*udst), "=&a" (eax) : "r" (byte));
522 +copy_in (void *dst_, const void *usrc_, size_t size)
524 + uint8_t *dst = dst_;
525 + const uint8_t *usrc = usrc_;
527 + for (; size > 0; size--, dst++, usrc++)
528 + if (usrc >= (uint8_t *) PHYS_BASE || !get_user (dst, usrc))
533 +copy_in_string (const char *us)
538 + ks = palloc_get (0);
541 + printf ("copy_in_string: out of memory\n");
545 + for (length = 0; length < PGSIZE; length++)
547 + if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++))
549 + printf ("bad user reference (%p)\n", us + length);
553 + if (ks[length] == '\0')
557 + printf ("copy_in_string: string too long\n");
569 +sys_exit (int ret_code)
571 + thread_current ()->ret_code = ret_code;
577 +sys_exec (const char *ufile)
580 + char *kfile = copy_in_string (ufile);
582 + lock_acquire (&fs_lock);
583 + tid = process_execute (kfile);
584 + lock_release (&fs_lock);
586 + palloc_free (kfile);
592 +sys_join (tid_t child)
594 + return thread_join (child);
598 +sys_create (const char *ufile, unsigned initial_size)
600 + char *kfile = copy_in_string (ufile);
603 + lock_acquire (&fs_lock);
604 + ok = filesys_create (kfile, initial_size);
605 + lock_release (&fs_lock);
607 + palloc_free (kfile);
613 +sys_remove (const char *ufile)
615 + char *kfile = copy_in_string (ufile);
618 + lock_acquire (&fs_lock);
619 + ok = filesys_remove (kfile);
620 + lock_release (&fs_lock);
622 + palloc_free (kfile);
635 +sys_open (const char *ufile)
637 + char *kfile = copy_in_string (ufile);
641 + fd = malloc (sizeof *fd);
645 + lock_acquire (&fs_lock);
646 + fd->file = filesys_open (kfile);
647 + if (fd->file != NULL)
649 + struct thread *cur = thread_current ();
650 + handle = fd->handle = cur->next_handle++;
651 + list_push_front (&cur->fds, &fd->elem);
655 + lock_release (&fs_lock);
658 + palloc_free (kfile);
662 +static struct fildes *
663 +lookup_fd (int handle)
665 + struct thread *cur = thread_current ();
668 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
671 + struct fildes *fd = list_entry (e, struct fildes, elem);
672 + if (fd->handle == handle)
676 + printf ("no handle %d\n", handle);
681 +sys_filesize (int handle)
683 + struct fildes *fd = lookup_fd (handle);
686 + lock_acquire (&fs_lock);
687 + size = file_length (fd->file);
688 + lock_release (&fs_lock);
694 +sys_read (int handle, void *udst_, unsigned size)
696 + uint8_t *udst = udst_;
698 + int bytes_read = 0;
700 + if (handle == STDIN_FILENO)
702 + for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
703 + if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, kbd_getc ()))
708 + lock_acquire (&fs_lock);
709 + fd = lookup_fd (handle);
712 + size_t page_left = PGSIZE - pg_ofs (udst);
713 + size_t read_amt = size < page_left ? size : page_left;
716 + if (!verify_user (udst))
718 + lock_release (&fs_lock);
722 + retval = file_read (fd->file, udst, read_amt);
725 + if (bytes_read == 0)
730 + bytes_read += retval;
731 + if (retval != (off_t) read_amt)
737 + lock_release (&fs_lock);
743 +sys_write (int handle, void *usrc_, unsigned size)
745 + uint8_t *usrc = usrc_;
746 + struct fildes *fd = NULL;
747 + int bytes_written = 0;
749 + lock_acquire (&fs_lock);
750 + if (handle != STDOUT_FILENO)
751 + fd = lookup_fd (handle);
754 + size_t page_left = PGSIZE - pg_ofs (usrc);
755 + size_t write_amt = size < page_left ? size : page_left;
758 + if (!verify_user (usrc))
760 + lock_release (&fs_lock);
764 + if (handle == STDOUT_FILENO)
766 + putbuf (usrc, write_amt);
767 + retval = write_amt;
770 + retval = file_write (fd->file, usrc, write_amt);
773 + if (bytes_written == 0)
774 + bytes_written = -1;
778 + bytes_written += retval;
779 + if (retval != (off_t) write_amt)
785 + lock_release (&fs_lock);
787 + return bytes_written;
791 +sys_seek (int handle, unsigned position)
793 + struct fildes *fd = lookup_fd (handle);
795 + lock_acquire (&fs_lock);
796 + file_seek (fd->file, position);
797 + lock_release (&fs_lock);
803 +sys_tell (int handle)
805 + struct fildes *fd = lookup_fd (handle);
808 + lock_acquire (&fs_lock);
809 + position = file_tell (fd->file);
810 + lock_release (&fs_lock);
816 +sys_close (int handle)
818 + struct fildes *fd = lookup_fd (handle);
819 + lock_acquire (&fs_lock);
820 + file_close (fd->file);
821 + lock_release (&fs_lock);
822 + list_remove (&fd->elem);
830 + struct thread *cur = thread_current ();
831 + list_elem *e, *next;
833 + for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
835 + struct fildes *fd = list_entry (e, struct fildes, elem);
836 + next = list_next (e);
837 + file_close (fd->file);
841 diff -urp pintos.orig/src/userprog/syscall.h pintos/src/userprog/syscall.h
842 --- pintos.orig/src/userprog/syscall.h 2004-09-05 22:38:45.000000000 -0700
843 +++ pintos/src/userprog/syscall.h 2004-09-22 00:30:05.000000000 -0700
845 #define USERPROG_SYSCALL_H
847 void syscall_init (void);
848 +void syscall_exit (void);
850 #endif /* userprog/syscall.h */