+/* Allocates a SIZE-byte frame at the top of thread T's stack and
+ returns a pointer to the frame's base. */
+static void *
+alloc_frame (struct thread *t, size_t size)
+{
+ /* Stack data is always allocated in word-size units. */
+ ASSERT (is_thread (t));
+ ASSERT (size % sizeof (uint32_t) == 0);
+
+ t->stack -= size;
+ return t->stack;
+}
+
+/* Chooses and returns the next thread to be scheduled. Should
+ return a thread from the run queue, unless the run queue is
+ empty. (If the running thread can continue running, then it
+ will be in the run queue.) If the run queue is empty, return
+ idle_thread. */
+static struct thread *
+next_thread_to_run (void)
+{
+ if (list_empty (&ready_list))
+ return idle_thread;
+ else
+ return list_entry (list_pop_front (&ready_list), struct thread, elem);
+}
+
+/* Completes a thread switch by activating the new thread's page
+ tables, and, if the previous thread is dying, destroying it.
+
+ At this function's invocation, we just switched from thread
+ PREV, the new thread is already running, and interrupts are
+ still disabled. This function is normally invoked by
+ thread_schedule() as its final action before returning, but
+ the first time a thread is scheduled it is called by
+ switch_entry() (see switch.S).
+
+ It's not safe to call printf() until the thread switch is
+ complete. In practice that means that printf()s should be
+ added at the end of the function.
+
+ After this function and its caller returns, the thread switch
+ is complete. */