X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fthreads%2Fthread.c;h=8a55699ded46cf7165715966950641aa7a2aca49;hb=ac7b54c81e81f4b7a4cc404b5aa21f46a5dbdddd;hp=1b56f98508e16922de88d299cf02ec2f6f0a22f1;hpb=18f1ad2798f7e7f93f61d42e24f72cfe8f195d4a;p=pintos-anon diff --git a/src/threads/thread.c b/src/threads/thread.c index 1b56f98..8a55699 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -3,32 +3,35 @@ #include #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 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. - This is the thread running main(). */ +/* 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 { @@ -39,15 +42,17 @@ 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); -static void init_thread (struct thread *, const char *name); +static struct thread *new_thread (const char *name, int priority); +static void init_thread (struct thread *, const char *name, int priority); static bool is_thread (struct thread *); 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 @@ -63,10 +68,13 @@ thread_init (void) { ASSERT (intr_get_level () == INTR_OFF); + lock_init (&tid_lock, "tid"); + /* Set up a thread structure for the running thread. */ initial_thread = running_thread (); - init_thread (initial_thread, "main"); + init_thread (initial_thread, "main", PRI_DEFAULT); initial_thread->status = THREAD_RUNNING; + initial_thread->tid = allocate_tid (); /* Initialize run queue. */ list_init (&ready_list); @@ -77,31 +85,39 @@ 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", PRI_DEFAULT, 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 * -thread_create (const char *name, thread_func *function, void *aux) +/* Creates a new kernel thread named NAME with the given initial + PRIORITY, 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. 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. + + The code provided sets the new thread's `priority' member to + PRIORITY, but no actual priority scheduling is implemented. + Priority scheduling is the goal of Problem 1-3. */ +tid_t +thread_create (const char *name, int priority, + 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); + t = new_thread (name, priority); + if (t == NULL) + return TID_ERROR; + tid = t->tid; /* Stack frame for kernel_thread(). */ kf = alloc_frame (t, sizeof *kf); @@ -120,7 +136,7 @@ thread_create (const char *name, thread_func *function, void *aux) /* Add to run queue. */ thread_unblock (t); - return t; + return tid; } #ifdef USERPROG @@ -128,7 +144,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; @@ -136,12 +152,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); + t = new_thread (filename, PRI_DEFAULT); if (t == NULL) - return false; + return TID_ERROR; + tid = t->tid; if (!addrspace_load (t, filename, &start)) PANIC ("%s: program load failed", filename); @@ -167,12 +185,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) @@ -182,20 +200,17 @@ thread_unblock (struct thread *t) ASSERT (is_thread (t)); old_level = intr_disable (); - if (t->status == THREAD_BLOCKED) - { - list_push_back (&ready_list, &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. @@ -217,6 +232,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 @@ -269,16 +291,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"); } } @@ -314,31 +337,36 @@ is_thread (struct thread *t) return t != NULL && t->magic == THREAD_MAGIC; } -/* Creates a new thread named NAME and initializes its fields. - Returns the new thread if successful or a null pointer on - failure. */ +/* Creates a new thread named NAME as a child of the running + thread. Returns the new thread if successful or a null + pointer on failure. */ static struct thread * -new_thread (const char *name) +new_thread (const char *name, int priority) { - struct thread *t; - - ASSERT (name != NULL); - - t = palloc_get (PAL_ZERO); - if (t != NULL) - init_thread (t, name); + struct thread *t = palloc_get (PAL_ZERO); + if (t != NULL) + { + init_thread (t, name, priority); + t->tid = allocate_tid (); + } return t; } -/* Initializes T as a new, blocked thread named NAME. */ +/* Does basic initialization of T as a new, blocked thread named + NAME. */ static void -init_thread (struct thread *t, const char *name) +init_thread (struct thread *t, const char *name, int priority) { + ASSERT (t != NULL); + ASSERT (PRI_MIN <= priority && priority <= PRI_MAX); + ASSERT (name != NULL); + 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->priority = priority; t->magic = THREAD_MAGIC; } @@ -438,6 +466,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. */