X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fthreads%2Fthread.c;h=a1c98a6c0564af07663b208f159026914080d728;hb=b0a700d18f0a0a8c87e1a4fff3a2108e0edb0fbc;hp=f24f1fe4b3777d729b8a5fdd3374946076d8cb1f;hpb=f6580e9ad405b519dbe85027691bf3c66074b0a4;p=pintos-anon diff --git a/src/threads/thread.c b/src/threads/thread.c index f24f1fe..a1c98a6 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -1,29 +1,36 @@ -#include "thread.h" +#include "threads/thread.h" +#include #include -#include "interrupt.h" -#include "intr-stubs.h" -#include "mmu.h" -#include "palloc.h" -#include "switch.h" -#include "lib/debug.h" -#include "lib/lib.h" -#include "lib/random.h" +#include +#include +#include "threads/flags.h" +#include "threads/interrupt.h" +#include "threads/intr-stubs.h" +#include "threads/mmu.h" +#include "threads/palloc.h" +#include "threads/switch.h" +#include "threads/synch.h" #ifdef USERPROG #include "userprog/gdt.h" #endif -/* Value for struct thread's `magic' member. +/* Random 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 +#define THREAD_MAGIC 0xcd6abf4b /* 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. */ +static struct thread *idle_thread; + +/* Initial thread, the thread running init.c:main(). */ +static struct thread *initial_thread; + +/* Lock used by allocate_tid(). */ +static struct lock tid_lock; /* Stack frame for kernel_thread(). */ struct kernel_thread_frame @@ -35,6 +42,7 @@ struct kernel_thread_frame static void kernel_thread (thread_func *, void *aux); +static void idle (void *aux UNUSED); static struct thread *running_thread (void); static struct thread *next_thread_to_run (void); static struct thread *new_thread (const char *name); @@ -44,6 +52,7 @@ static void *alloc_frame (struct thread *, size_t size); static void destroy_thread (struct thread *); static void schedule (void); void schedule_tail (struct thread *prev); +static tid_t allocate_tid (void); /* Initializes the threading system by transforming the code that's currently running into a thread. Note that this is @@ -57,17 +66,18 @@ void schedule_tail (struct thread *prev); void thread_init (void) { - struct thread *t; - ASSERT (intr_get_level () == INTR_OFF); + lock_init (&tid_lock, "tid"); + /* 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; + initial_thread->tid = allocate_tid (); /* Initialize run queue. */ - list_init (&run_queue); + list_init (&ready_list); } /* Starts preemptive thread scheduling by enabling interrupts. @@ -75,31 +85,33 @@ thread_init (void) void thread_start (void) { - /* Create idle thread. */ - idle_thread = thread_create ("idle", idle, NULL); - idle_thread->status = THREAD_BLOCKED; - - /* Enable interrupts. */ + thread_create ("idle", idle, NULL); intr_enable (); } /* Creates a new kernel thread named NAME, which executes FUNCTION passing AUX as the argument, and adds it to the ready queue. If thread_start() has been called, then the new thread - may be scheduled before thread_create() returns. Use a - semaphore or some other form of synchronization if you need to - ensure ordering. */ -struct thread * + may be scheduled before thread_create() returns. It could + even exit before thread_create() returns. Use a semaphore or + some other form of synchronization if you need to ensure + ordering. Returns the thread identifier for the new thread, + or TID_ERROR if creation fails. */ +tid_t thread_create (const char *name, thread_func *function, void *aux) { struct thread *t; struct kernel_thread_frame *kf; struct switch_entry_frame *ef; struct switch_threads_frame *sf; + tid_t tid; ASSERT (function != NULL); t = new_thread (name); + if (t == NULL) + return TID_ERROR; + tid = t->tid = allocate_tid (); /* Stack frame for kernel_thread(). */ kf = alloc_frame (t, sizeof *kf); @@ -118,7 +130,7 @@ thread_create (const char *name, thread_func *function, void *aux) /* Add to run queue. */ thread_unblock (t); - return t; + return tid; } #ifdef USERPROG @@ -126,7 +138,7 @@ thread_create (const char *name, thread_func *function, void *aux) FILENAME, and adds it to the ready queue. If thread_start() has been called, then new thread may be scheduled before thread_execute() returns.*/ -bool +tid_t thread_execute (const char *filename) { struct thread *t; @@ -134,12 +146,14 @@ thread_execute (const char *filename) struct switch_entry_frame *ef; struct switch_threads_frame *sf; void (*start) (void); + tid_t tid; ASSERT (filename != NULL); t = new_thread (filename); if (t == NULL) - return false; + return TID_ERROR; + tid = t->tid = allocate_tid (); if (!addrspace_load (t, filename, &start)) PANIC ("%s: program load failed", filename); @@ -165,12 +179,12 @@ thread_execute (const char *filename) /* Add to run queue. */ thread_unblock (t); - return true; + return tid; } #endif /* Transitions a blocked thread T from its current state to the - ready-to-run state. If T is not blocked, there is no effect. + ready-to-run state. This is an error if T is not blocked. (Use thread_yield() to make the running thread ready.) */ void thread_unblock (struct thread *t) @@ -180,20 +194,17 @@ thread_unblock (struct thread *t) ASSERT (is_thread (t)); old_level = intr_disable (); - if (t->status == THREAD_BLOCKED) - { - list_push_back (&run_queue, &t->elem); - t->status = THREAD_READY; - } + ASSERT (t->status == THREAD_BLOCKED); + list_push_back (&ready_list, &t->elem); + t->status = THREAD_READY; intr_set_level (old_level); } -/* Returns the name of thread T. */ +/* Returns the name of the running thread. */ const char * -thread_name (struct thread *t) +thread_name (void) { - ASSERT (is_thread (t)); - return t->name; + return thread_current ()->name; } /* Returns the running thread. @@ -215,6 +226,13 @@ thread_current (void) return t; } +/* Returns the running thread's tid. */ +tid_t +thread_tid (void) +{ + return thread_current ()->tid; +} + /* Deschedules the current thread and destroys it. Never returns to the caller. */ void @@ -241,7 +259,7 @@ thread_yield (void) ASSERT (!intr_context ()); old_level = intr_disable (); - list_push_back (&run_queue, &cur->elem); + list_push_back (&ready_list, &cur->elem); cur->status = THREAD_READY; schedule (); intr_set_level (old_level); @@ -267,16 +285,17 @@ thread_block (void) static void idle (void *aux UNUSED) { + idle_thread = thread_current (); + for (;;) { - /* Wait for an interrupt. */ - DEBUG (idle, "idle"); - asm ("hlt"); - /* Let someone else run. */ intr_disable (); thread_block (); intr_enable (); + + /* Use CPU `hlt' instruction to wait for interrupt. */ + asm ("hlt"); } } @@ -334,9 +353,9 @@ static void init_thread (struct thread *t, const char *name) { memset (t, 0, sizeof *t); + t->status = THREAD_BLOCKED; strlcpy (t->name, name, sizeof t->name); t->stack = (uint8_t *) t + PGSIZE; - t->status = THREAD_BLOCKED; t->magic = THREAD_MAGIC; } @@ -361,10 +380,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, 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 @@ -379,7 +398,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 @@ -435,6 +455,20 @@ schedule (void) prev = switch_threads (cur, next); schedule_tail (prev); } + +/* Returns a tid to use for a new thread. */ +static tid_t +allocate_tid (void) +{ + static tid_t next_tid = 1; + tid_t tid; + + lock_acquire (&tid_lock); + tid = next_tid++; + lock_release (&tid_lock); + + return tid; +} /* Offset of `stack' member within `struct thread'. Used by switch.S, which can't figure it out on its own. */