- added thread_foreach
authorGodmar Back <godmar@gmail.com>
Wed, 27 Aug 2008 16:52:04 +0000 (16:52 +0000)
committerGodmar Back <godmar@gmail.com>
Wed, 27 Aug 2008 16:52:04 +0000 (16:52 +0000)
- added debug_backtrace_all
- updated P1 solution to take advantage of this new code

src/lib/debug.h
src/lib/kernel/debug.c
src/threads/thread.c
src/threads/thread.h

index 3218ab61360d8753c113674005dd8890d584aa95..888ab7b9d985d96033f9ee3c00a2876476256a7c 100644 (file)
@@ -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
 
index 93c395208068801dcdbca3b4dffbec7b64c74712..22801954dd66512d489287a629371c6d88133ecf 100644 (file)
@@ -7,6 +7,9 @@
 #include <string.h>
 #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);
+}
index 92d1aa899efe1d8bf84c6c7056ae7d45215c687b..2532463bdbbf5d8f2544cba0b590ae070d2d07e1 100644 (file)
    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
index 0039560018ddc942fb2f10002ddd4d94e3045b8c..7965c0607815eab3275da7babdf669177f18c8e2 100644 (file)
@@ -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);