From: Godmar Back Date: Wed, 27 Aug 2008 16:52:04 +0000 (+0000) Subject: - added thread_foreach X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pintos-anon;a=commitdiff_plain;h=3edcfedb8e62970f3293fa676b6691f8658c3c11 - added thread_foreach - added debug_backtrace_all - updated P1 solution to take advantage of this new code --- diff --git a/src/lib/debug.h b/src/lib/debug.h index 3218ab6..888ab7b 100644 --- a/src/lib/debug.h +++ b/src/lib/debug.h @@ -16,6 +16,7 @@ void debug_panic (const char *file, int line, const char *function, const char *message, ...) PRINTF_FORMAT (4, 5) NO_RETURN; void debug_backtrace (void); +void debug_backtrace_all (void); #endif diff --git a/src/lib/kernel/debug.c b/src/lib/kernel/debug.c index 93c3952..2280195 100644 --- a/src/lib/kernel/debug.c +++ b/src/lib/kernel/debug.c @@ -7,6 +7,9 @@ #include #include "threads/init.h" #include "threads/interrupt.h" +#include "threads/thread.h" +#include "threads/switch.h" +#include "threads/vaddr.h" #include "devices/serial.h" /* Halts the OS, printing the source file name, line number, and @@ -46,3 +49,75 @@ debug_panic (const char *file, int line, const char *function, power_off (); for (;;); } + +/* Print call stack of a thread. + The thread may be running, ready, or blocked. */ +static void +print_stacktrace(struct thread *t, void *aux UNUSED) +{ + void *retaddr = NULL, **frame = NULL; + const char *status = "UNKNOWN"; + + switch (t->status) { + case THREAD_RUNNING: + status = "RUNNING"; + break; + + case THREAD_READY: + status = "READY"; + break; + + case THREAD_BLOCKED: + status = "BLOCKED"; + break; + + default: + break; + } + + printf ("Call stack of thread `%s' (status %s):", t->name, status); + + if (t == thread_current()) + { + frame = __builtin_frame_address (1); + retaddr = __builtin_return_address (0); + } + else + { + /* Retrieve the values of the base and instruction pointers + as they were saved when this thread called switch_threads. */ + struct switch_threads_frame * saved_frame; + + saved_frame = (struct switch_threads_frame *)t->stack; + + /* Skip threads if they have been added to the all threads + list, but have never been scheduled. + We can identify because their `stack' member either points + at the top of their kernel stack page, or the + switch_threads_frame's 'eip' member points at switch_entry. + See also threads.c. */ + if (t->stack == (uint8_t *)t + PGSIZE || saved_frame->eip == switch_entry) + { + printf (" thread was never scheduled.\n"); + return; + } + + frame = (void **) saved_frame->ebp; + retaddr = (void *) saved_frame->eip; + } + + printf (" %p", retaddr); + for (; (uintptr_t) frame >= 0x1000 && frame[0] != NULL; frame = frame[0]) + printf (" %p", frame[1]); + printf (".\n"); +} + +/* Prints call stack of all threads. */ +void +debug_backtrace_all (void) +{ + enum intr_level oldlevel = intr_disable (); + + thread_foreach (print_stacktrace, 0); + intr_set_level (oldlevel); +} diff --git a/src/threads/thread.c b/src/threads/thread.c index 92d1aa8..2532463 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -24,6 +24,10 @@ that are ready to run but not actually running. */ static struct list ready_list; +/* List of all processes. Processes are added to this list + when they are first scheduled and removed when they exit. */ +static struct list all_list; + /* Idle thread. */ static struct thread *idle_thread; @@ -87,6 +91,7 @@ thread_init (void) lock_init (&tid_lock); list_init (&ready_list); + list_init (&all_list); /* Set up a thread structure for the running thread. */ initial_thread = running_thread (); @@ -166,6 +171,7 @@ thread_create (const char *name, int priority, struct switch_entry_frame *ef; struct switch_threads_frame *sf; tid_t tid; + enum intr_level old_level; ASSERT (function != NULL); @@ -178,6 +184,11 @@ thread_create (const char *name, int priority, init_thread (t, name, priority); tid = t->tid = allocate_tid (); + /* Prepare thread for first run by initializing its stack. + Do this atomically so intermediate values for the 'stack' + member cannot be observed. */ + old_level = intr_disable (); + /* Stack frame for kernel_thread(). */ kf = alloc_frame (t, sizeof *kf); kf->eip = NULL; @@ -191,6 +202,9 @@ thread_create (const char *name, int priority, /* Stack frame for switch_threads(). */ sf = alloc_frame (t, sizeof *sf); sf->eip = switch_entry; + sf->ebp = 0; + + intr_set_level (old_level); /* Add to run queue. */ thread_unblock (t); @@ -280,9 +294,11 @@ thread_exit (void) process_exit (); #endif - /* Just set our status to dying and schedule another process. - We will be destroyed during the call to schedule_tail(). */ + /* Remove thread from all threads list, set our status to dying, + and schedule another process. That process will destroy us + when it call schedule_tail(). */ intr_disable (); + list_remove (&thread_current()->allelem); thread_current ()->status = THREAD_DYING; schedule (); NOT_REACHED (); @@ -306,6 +322,23 @@ thread_yield (void) intr_set_level (old_level); } +/* Invoke function 'func' on all threads, passing along 'aux'. + This function must be called with interrupts off. */ +void +thread_foreach (thread_action_func *func, void *aux) +{ + struct list_elem *e; + + ASSERT (intr_get_level () == INTR_OFF); + + for (e = list_begin (&all_list); e != list_end (&all_list); + e = list_next (e)) + { + struct thread *t = list_entry (e, struct thread, allelem); + func (t, aux); + } +} + /* Sets the current thread's priority to NEW_PRIORITY. */ void thread_set_priority (int new_priority) @@ -436,6 +469,7 @@ init_thread (struct thread *t, const char *name, int priority) t->stack = (uint8_t *) t + PGSIZE; t->priority = priority; t->magic = THREAD_MAGIC; + list_push_back (&all_list, &t->allelem); } /* Allocates a SIZE-byte frame at the top of thread T's stack and diff --git a/src/threads/thread.h b/src/threads/thread.h index 0039560..7965c06 100644 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -88,6 +88,7 @@ struct thread char name[16]; /* Name (for debugging purposes). */ uint8_t *stack; /* Saved stack pointer. */ int priority; /* Priority. */ + struct list_elem allelem; /* List element for all threads list. */ /* Shared between thread.c and synch.c. */ struct list_elem elem; /* List element. */ @@ -125,6 +126,10 @@ const char *thread_name (void); void thread_exit (void) NO_RETURN; void thread_yield (void); +/* Performs some operation on thread t, given auxiliary data AUX. */ +typedef void thread_action_func (struct thread *t, void *aux); +void thread_foreach (thread_action_func *, void *); + int thread_get_priority (void); void thread_set_priority (int);