X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fthreads%2Fthread.c;h=218305c00a140384e20d2ffa42a9597b40970cf7;hb=8063d8f3b3a778e9a15eff66dfd1b08652bae523;hp=04b446f9f475d0225b45b4f6e6d797a12defbd87;hpb=987024569c1e5e9468238849dd79ec8d386352e6;p=pintos-anon diff --git a/src/threads/thread.c b/src/threads/thread.c index 04b446f..218305c 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -2,6 +2,7 @@ #include #include "debug.h" #include "interrupt.h" +#include "intr-stubs.h" #include "lib.h" #include "mmu.h" #include "palloc.h" @@ -11,11 +12,28 @@ uint32_t thread_stack_ofs = offsetof (struct thread, stack); static struct list run_queue; +static struct thread *idle_thread; + +static void +idle (void *aux UNUSED) +{ + for (;;) + { + /* Wait for an interrupt. */ + asm ("hlt"); + + /* Let someone else run. */ + intr_disable (); + thread_sleep (); + intr_enable (); + } +} void thread_init (void) { list_init (&run_queue); + idle_thread = thread_create ("idle", idle, NULL); } struct thread_root_frame @@ -29,7 +47,8 @@ static void thread_root (void (*function) (void *aux), void *aux) { ASSERT (function != NULL); - + + intr_enable (); function (aux); thread_exit (); } @@ -66,8 +85,8 @@ thread_create (const char *name, void (*function) (void *aux), void *aux) { struct thread *t; struct thread_root_frame *rf; - struct switch_thunk_frame *tf; - struct switch_frame *sf; + struct switch_entry_frame *ef; + struct switch_threads_frame *sf; ASSERT (function != NULL); @@ -79,13 +98,13 @@ thread_create (const char *name, void (*function) (void *aux), void *aux) rf->function = function; rf->aux = aux; - /* Stack frame for switch_thunk(). */ - tf = alloc_frame (t, sizeof *tf); - tf->eip = (void (*) (void)) thread_root; + /* Stack frame for switch_entry(). */ + ef = alloc_frame (t, sizeof *ef); + ef->eip = (void (*) (void)) thread_root; /* Stack frame for thread_switch(). */ sf = alloc_frame (t, sizeof *sf); - sf->eip = (void (*) (void)) switch_thunk; + sf->eip = switch_entry; /* Add to run queue. */ thread_ready (t); @@ -105,13 +124,42 @@ thread_current (void) bool thread_execute (const char *filename) { - struct thread *t = new_thread (filename); + struct thread *t; + struct intr_frame *if_; + struct switch_entry_frame *ef; + struct switch_threads_frame *sf; + void (*start) (void); + + ASSERT (filename != NULL); + + t = new_thread (filename); if (t == NULL) return false; - if (!addrspace_load (&t->addrspace, filename)) + if (!addrspace_load (&t->addrspace, filename, &start)) panic ("%s: program load failed", filename); - printk ("%s: loaded\n", filename); + + /* Interrupt frame. */ + if_ = alloc_frame (t, sizeof *if_); + if_->es = SEL_UDSEG; + if_->ds = SEL_UDSEG; + if_->eip = start; + if_->cs = SEL_UCSEG; + if_->eflags = FLAG_IF | 2; + if_->esp = PHYS_BASE; + if_->ss = SEL_UDSEG; + + /* Stack frame for switch_entry(). */ + ef = alloc_frame (t, sizeof *ef); + ef->eip = intr_exit; + + /* Stack frame for thread_switch(). */ + sf = alloc_frame (t, sizeof *sf); + sf->eip = switch_entry; + + /* Add to run queue. */ + thread_ready (t); + return true; } #endif @@ -135,14 +183,6 @@ find_next_to_run (void) return list_entry (list_pop_front (&run_queue), struct thread, rq_elem); } -static void -idle (void) -{ - static int idle = 0; - if (idle++ == 0) - printk ("idle\n"); -} - void thread_destroy (struct thread *t) { @@ -152,7 +192,26 @@ thread_destroy (struct thread *t) palloc_free (t); } +void schedule_tail (struct thread *prev); + void +schedule_tail (struct thread *prev) +{ +#ifdef USERPROG + struct thread *cur = thread_current (); +#endif + + ASSERT (intr_get_level () == IF_OFF); + +#ifdef USERPROG + addrspace_activate (&cur->addrspace); +#endif + + if (prev != NULL && prev->status == THREAD_DYING) + thread_destroy (prev); +} + +static void thread_schedule (void) { struct thread *cur, *next, *prev; @@ -162,34 +221,34 @@ thread_schedule (void) cur = thread_current (); ASSERT (cur->status != THREAD_RUNNING); - while ((next = find_next_to_run ()) == NULL) - idle (); + next = find_next_to_run (); + if (next == NULL) + next = idle_thread; next->status = THREAD_RUNNING; - prev = switch_threads (cur, next); + if (cur != next) + { + prev = switch_threads (cur, next); - /* Prevent GCC from reordering anything around the thread - switch. */ - asm volatile ("" : : : "memory"); + /* Prevent GCC from reordering anything around the thread + switch. */ + asm volatile ("" : : : "memory"); -#ifdef USERPROG - addrspace_activate (&cur->addrspace); -#endif - - if (prev != NULL && prev->status == THREAD_DYING) - thread_destroy (prev); - - intr_enable (); + schedule_tail (prev); + } } void thread_yield (void) { + enum if_level old_level; + ASSERT (!intr_context ()); - intr_disable (); + old_level = intr_disable (); thread_ready (thread_current ()); thread_schedule (); + intr_set_level (old_level); } void @@ -201,6 +260,7 @@ thread_start (struct thread *t) list_remove (&t->rq_elem); t->status = THREAD_RUNNING; switch_threads (NULL, t); + NOT_REACHED (); } void @@ -211,6 +271,7 @@ thread_exit (void) intr_disable (); thread_current ()->status = THREAD_DYING; thread_schedule (); + NOT_REACHED (); } void