#include <debug.h>
#include <stddef.h>
#include <random.h>
+#include <stdio.h>
#include <string.h>
#include "threads/flags.h"
#include "threads/interrupt.h"
#include "threads/switch.h"
#include "threads/synch.h"
#ifdef USERPROG
-#include "userprog/gdt.h"
+#include "userprog/process.h"
#endif
/* Random value for struct thread's `magic' member.
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, 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);
ASSERT (intr_get_level () == INTR_OFF);
lock_init (&tid_lock, "tid");
+ list_init (&ready_list);
/* Set up a thread structure for the running thread. */
initial_thread = running_thread ();
init_thread (initial_thread, "main", PRI_DEFAULT);
initial_thread->status = THREAD_RUNNING;
initial_thread->tid = allocate_tid ();
-
- /* Initialize run queue. */
- list_init (&ready_list);
}
/* Starts preemptive thread scheduling by enabling interrupts.
ASSERT (function != NULL);
- t = new_thread (name, priority);
+ /* Allocate thread. */
+ t = palloc_get_page (PAL_ZERO);
if (t == NULL)
return TID_ERROR;
- tid = t->tid;
+
+ /* Initialize thread. */
+ init_thread (t, name, priority);
+ tid = t->tid = allocate_tid ();
/* Stack frame for kernel_thread(). */
kf = alloc_frame (t, sizeof *kf);
return tid;
}
-#ifdef USERPROG
-/* Starts a new thread running a user program loaded from
- FILENAME, and adds it to the ready queue. If thread_start()
- has been called, then new thread may be scheduled before
- thread_execute() returns.*/
-tid_t
-thread_execute (const char *filename)
-{
- struct thread *t;
- struct intr_frame *if_;
- struct switch_entry_frame *ef;
- struct switch_threads_frame *sf;
- void (*start) (void);
- tid_t tid;
-
- ASSERT (filename != NULL);
-
- t = new_thread (filename, PRI_DEFAULT);
- if (t == NULL)
- return TID_ERROR;
- tid = t->tid;
-
- if (!addrspace_load (t, filename, &start))
- PANIC ("%s: program load failed", filename);
-
- /* Interrupt frame. */
- if_ = alloc_frame (t, sizeof *if_);
- if_->es = SEL_UDSEG;
- if_->ds = SEL_UDSEG;
- if_->eip = start;
- if_->cs = SEL_UCSEG;
- if_->eflags = FLAG_IF | FLAG_MBS;
- if_->esp = PHYS_BASE;
- if_->ss = SEL_UDSEG;
-
- /* Stack frame for switch_entry(). */
- ef = alloc_frame (t, sizeof *ef);
- ef->eip = intr_exit;
-
- /* Stack frame for switch_threads(). */
- sf = alloc_frame (t, sizeof *sf);
- sf->eip = switch_entry;
-
- /* Add to run queue. */
- thread_unblock (t);
-
- return tid;
-}
-#endif
-
/* Transitions a blocked thread T from its current state to the
ready-to-run state. This is an error if T is not blocked.
(Use thread_yield() to make the running thread ready.) */
{
ASSERT (!intr_context ());
+#ifdef USERPROG
+ process_exit ();
+#endif
+
/* Just set our status to dying and schedule another process.
We will be destroyed during the call to schedule_tail(). */
intr_disable ();
return t != NULL && t->magic == THREAD_MAGIC;
}
-/* 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, int priority)
-{
- struct thread *t = palloc_get (PAL_ZERO);
- if (t != NULL)
- {
- init_thread (t, name, priority);
- t->tid = allocate_tid ();
- }
-
- return t;
-}
-
-/* Does basic initialization of T as a new, blocked thread named
+/* Does basic initialization of T as a blocked thread named
NAME. */
static void
init_thread (struct thread *t, const char *name, int priority)
return list_entry (list_pop_front (&ready_list), struct thread, elem);
}
-/* Destroys T, which must be in the dying state and must not be
- the running thread. */
-static void
-destroy_thread (struct thread *t)
-{
- ASSERT (is_thread (t));
- ASSERT (t->status == THREAD_DYING);
- ASSERT (t != thread_current ());
-
-#ifdef USERPROG
- addrspace_destroy (t);
-#endif
- if (t != initial_thread)
- palloc_free (t);
-}
-
/* Completes a thread switch by activating the new thread's page
tables, and, if the previous thread is dying, destroying it.
#ifdef USERPROG
/* Activate the new address space. */
- addrspace_activate (cur);
+ process_activate ();
#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 the thread we switched from is dying, destroy its struct
+ thread. This must happen late so that thread_exit() doesn't
+ pull out the rug under itself. */
if (prev != NULL && prev->status == THREAD_DYING)
- destroy_thread (prev);
+ {
+ ASSERT (prev != cur);
+ if (prev != initial_thread)
+ palloc_free_page (prev);
+ }
}
/* Schedules a new process. At entry, interrupts must be off and