X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fthreads%2Fthread.c;h=1b56f98508e16922de88d299cf02ec2f6f0a22f1;hb=fcf89ebe9fe61d0a1739bd48b7dd90905aab461d;hp=7b34722777e6ae1beb14cb4b44cc23b633064a7a;hpb=828d300fd2039b686b69244c2bd6f8b87645086d;p=pintos-anon diff --git a/src/threads/thread.c b/src/threads/thread.c index 7b34722..1b56f98 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -1,27 +1,34 @@ -#include "thread.h" +#include "threads/thread.h" +#include #include -#include "debug.h" -#include "interrupt.h" -#include "intr-stubs.h" -#include "lib.h" -#include "mmu.h" -#include "palloc.h" -#include "random.h" -#include "switch.h" +#include +#include +#include "threads/interrupt.h" +#include "threads/intr-stubs.h" +#include "threads/mmu.h" +#include "threads/palloc.h" +#include "threads/switch.h" #ifdef USERPROG -#include "gdt.h" +#include "userprog/gdt.h" #endif +/* Value for struct thread's `magic' member. + Used to detect stack overflow. See the big comment at the top + of thread.h for details. */ #define THREAD_MAGIC 0x1234abcdu /* List of processes in THREAD_READY state, that is, processes that are ready to run but not actually running. */ -static struct list run_queue; +static struct list ready_list; /* Idle thread. */ static struct thread *idle_thread; /* Thread. */ static void idle (void *aux UNUSED); /* Thread function. */ +/* Initial thread. + This is the thread running main(). */ +static struct thread *initial_thread; + /* Stack frame for kernel_thread(). */ struct kernel_thread_frame { @@ -54,17 +61,15 @@ void schedule_tail (struct thread *prev); void thread_init (void) { - struct thread *t; - ASSERT (intr_get_level () == INTR_OFF); /* Set up a thread structure for the running thread. */ - t = running_thread (); - init_thread (t, "main"); - t->status = THREAD_RUNNING; + initial_thread = running_thread (); + init_thread (initial_thread, "main"); + initial_thread->status = THREAD_RUNNING; /* Initialize run queue. */ - list_init (&run_queue); + list_init (&ready_list); } /* Starts preemptive thread scheduling by enabling interrupts. @@ -113,7 +118,7 @@ thread_create (const char *name, thread_func *function, void *aux) sf->eip = switch_entry; /* Add to run queue. */ - thread_wake (t); + thread_unblock (t); return t; } @@ -160,25 +165,29 @@ thread_execute (const char *filename) sf->eip = switch_entry; /* Add to run queue. */ - thread_wake (t); + thread_unblock (t); return true; } #endif -/* Transitions T from its current state to THREAD_READY, the - ready-to-run state. On entry, T must be ready or blocked. +/* Transitions a blocked thread T from its current state to the + ready-to-run state. If T is not blocked, there is no effect. (Use thread_yield() to make the running thread ready.) */ void -thread_wake (struct thread *t) +thread_unblock (struct thread *t) { + enum intr_level old_level; + ASSERT (is_thread (t)); - ASSERT (t->status == THREAD_READY || t->status == THREAD_BLOCKED); - if (t->status != THREAD_READY) + + old_level = intr_disable (); + if (t->status == THREAD_BLOCKED) { - list_push_back (&run_queue, &t->rq_elem); + list_push_back (&ready_list, &t->elem); t->status = THREAD_READY; } + intr_set_level (old_level); } /* Returns the name of thread T. */ @@ -190,7 +199,8 @@ thread_name (struct thread *t) } /* Returns the running thread. - This is running_thread() plus a couple of sanity checks. */ + This is running_thread() plus a couple of sanity checks. + See the big comment at the top of thread.h for details. */ struct thread * thread_current (void) { @@ -214,6 +224,8 @@ thread_exit (void) { ASSERT (!intr_context ()); + /* Just set our status to dying and schedule another process. + We will be destroyed during the call to schedule_tail(). */ intr_disable (); thread_current ()->status = THREAD_DYING; schedule (); @@ -231,16 +243,20 @@ thread_yield (void) ASSERT (!intr_context ()); old_level = intr_disable (); - list_push_back (&run_queue, &cur->rq_elem); + list_push_back (&ready_list, &cur->elem); cur->status = THREAD_READY; schedule (); intr_set_level (old_level); } /* Puts the current thread to sleep. It will not be scheduled - again until awoken by thread_wake(). */ + again until awoken by thread_unblock(). + + This function must be called with interrupts turned off. It + is usually a better idea to use one of the synchronization + primitives in synch.h. */ void -thread_sleep (void) +thread_block (void) { ASSERT (!intr_context ()); ASSERT (intr_get_level () == INTR_OFF); @@ -261,7 +277,7 @@ idle (void *aux UNUSED) /* Let someone else run. */ intr_disable (); - thread_sleep (); + thread_block (); intr_enable (); } } @@ -315,7 +331,7 @@ new_thread (const char *name) return t; } -/* Initializes T as a new thread named NAME. */ +/* Initializes T as a new, blocked thread named NAME. */ static void init_thread (struct thread *t, const char *name) { @@ -347,10 +363,10 @@ alloc_frame (struct thread *t, size_t size) static struct thread * next_thread_to_run (void) { - if (list_empty (&run_queue)) + if (list_empty (&ready_list)) return idle_thread; else - return list_entry (list_pop_front (&run_queue), struct thread, rq_elem); + return list_entry (list_pop_front (&ready_list), struct thread, elem); } /* Destroys T, which must be in the dying state and must not be @@ -365,7 +381,8 @@ destroy_thread (struct thread *t) #ifdef USERPROG addrspace_destroy (t); #endif - palloc_free (t); + if (t != initial_thread) + palloc_free (t); } /* Completes a thread switch by activating the new thread's page @@ -387,13 +404,19 @@ schedule_tail (struct thread *prev) ASSERT (intr_get_level () == INTR_OFF); + /* Mark us as running. */ cur->status = THREAD_RUNNING; - if (prev != NULL && prev->status == THREAD_DYING) - destroy_thread (prev); #ifdef USERPROG + /* Activate the new address space. */ addrspace_activate (cur); #endif + + /* If the thread we switched from is dying, destroy it. + This must happen late because it's not a good idea to + e.g. destroy the page table you're currently using. */ + if (prev != NULL && prev->status == THREAD_DYING) + destroy_thread (prev); } /* Schedules a new process. At entry, interrupts must be off and