1 #include "threads/thread.h"
7 #include "threads/flags.h"
8 #include "threads/interrupt.h"
9 #include "threads/intr-stubs.h"
10 #include "threads/mmu.h"
11 #include "threads/palloc.h"
12 #include "threads/switch.h"
13 #include "threads/synch.h"
15 #include "userprog/process.h"
18 /* Random value for struct thread's `magic' member.
19 Used to detect stack overflow. See the big comment at the top
20 of thread.h for details. */
21 #define THREAD_MAGIC 0xcd6abf4b
23 /* List of processes in THREAD_READY state, that is, processes
24 that are ready to run but not actually running. */
25 static struct list ready_list;
28 static struct thread *idle_thread;
30 /* Initial thread, the thread running init.c:main(). */
31 static struct thread *initial_thread;
33 /* Lock used by allocate_tid(). */
34 static struct lock tid_lock;
36 /* Stack frame for kernel_thread(). */
37 struct kernel_thread_frame
39 void *eip; /* Return address. */
40 thread_func *function; /* Function to call. */
41 void *aux; /* Auxiliary data for function. */
44 static void kernel_thread (thread_func *, void *aux);
46 static void idle (void *aux UNUSED);
47 static struct thread *running_thread (void);
48 static struct thread *next_thread_to_run (void);
49 static void init_thread (struct thread *, const char *name, int priority);
50 static bool is_thread (struct thread *);
51 static void *alloc_frame (struct thread *, size_t size);
52 static void destroy_thread (struct thread *);
53 static void schedule (void);
54 void schedule_tail (struct thread *prev);
55 static tid_t allocate_tid (void);
57 /* Initializes the threading system by transforming the code
58 that's currently running into a thread. Note that this is
59 possible only because the loader was careful to put the bottom
60 of the stack at a page boundary; it won't work in general.
61 Also initializes the run queue.
63 After calling this function, be sure to initialize the page
64 allocator before trying to create any threads with
69 ASSERT (intr_get_level () == INTR_OFF);
71 lock_init (&tid_lock, "tid");
72 list_init (&ready_list);
74 /* Set up a thread structure for the running thread. */
75 initial_thread = running_thread ();
76 init_thread (initial_thread, "main", PRI_DEFAULT);
77 initial_thread->status = THREAD_RUNNING;
78 initial_thread->tid = allocate_tid ();
81 /* Starts preemptive thread scheduling by enabling interrupts.
82 Also creates the idle thread. */
86 thread_create ("idle", PRI_DEFAULT, idle, NULL);
90 /* Creates a new kernel thread named NAME with the given initial
91 PRIORITY, which executes FUNCTION passing AUX as the argument,
92 and adds it to the ready queue. If thread_start() has been
93 called, then the new thread may be scheduled before
94 thread_create() returns. It could even exit before
95 thread_create() returns. Use a semaphore or some other form
96 of synchronization if you need to ensure ordering. Returns
97 the thread identifier for the new thread, or TID_ERROR if
100 The code provided sets the new thread's `priority' member to
101 PRIORITY, but no actual priority scheduling is implemented.
102 Priority scheduling is the goal of Problem 1-3. */
104 thread_create (const char *name, int priority,
105 thread_func *function, void *aux)
108 struct kernel_thread_frame *kf;
109 struct switch_entry_frame *ef;
110 struct switch_threads_frame *sf;
113 ASSERT (function != NULL);
115 /* Allocate thread. */
116 t = palloc_get (PAL_ZERO);
120 /* Initialize thread. */
121 init_thread (t, name, priority);
122 tid = t->tid = allocate_tid ();
124 /* Stack frame for kernel_thread(). */
125 kf = alloc_frame (t, sizeof *kf);
127 kf->function = function;
130 /* Stack frame for switch_entry(). */
131 ef = alloc_frame (t, sizeof *ef);
132 ef->eip = (void (*) (void)) kernel_thread;
134 /* Stack frame for switch_threads(). */
135 sf = alloc_frame (t, sizeof *sf);
136 sf->eip = switch_entry;
138 /* Add to run queue. */
144 /* Transitions a blocked thread T from its current state to the
145 ready-to-run state. This is an error if T is not blocked.
146 (Use thread_yield() to make the running thread ready.) */
148 thread_unblock (struct thread *t)
150 enum intr_level old_level;
152 ASSERT (is_thread (t));
154 old_level = intr_disable ();
155 ASSERT (t->status == THREAD_BLOCKED);
156 list_push_back (&ready_list, &t->elem);
157 t->status = THREAD_READY;
158 intr_set_level (old_level);
161 /* Returns the name of the running thread. */
165 return thread_current ()->name;
168 /* Returns the running thread.
169 This is running_thread() plus a couple of sanity checks.
170 See the big comment at the top of thread.h for details. */
172 thread_current (void)
174 struct thread *t = running_thread ();
176 /* Make sure T is really a thread.
177 If either of these assertions fire, then your thread may
178 have overflowed its stack. Each thread has less than 4 kB
179 of stack, so a few big automatic arrays or moderate
180 recursion can cause stack overflow. */
181 ASSERT (is_thread (t));
182 ASSERT (t->status == THREAD_RUNNING);
187 /* Returns the running thread's tid. */
191 return thread_current ()->tid;
194 /* Deschedules the current thread and destroys it. Never
195 returns to the caller. */
199 ASSERT (!intr_context ());
201 /* Just set our status to dying and schedule another process.
202 We will be destroyed during the call to schedule_tail(). */
204 thread_current ()->status = THREAD_DYING;
209 /* Yields the CPU. The current thread is not put to sleep and
210 may be scheduled again immediately at the scheduler's whim. */
214 struct thread *cur = thread_current ();
215 enum intr_level old_level;
217 ASSERT (!intr_context ());
219 old_level = intr_disable ();
220 list_push_back (&ready_list, &cur->elem);
221 cur->status = THREAD_READY;
223 intr_set_level (old_level);
226 /* Puts the current thread to sleep. It will not be scheduled
227 again until awoken by thread_unblock().
229 This function must be called with interrupts turned off. It
230 is usually a better idea to use one of the synchronization
231 primitives in synch.h. */
235 ASSERT (!intr_context ());
236 ASSERT (intr_get_level () == INTR_OFF);
238 thread_current ()->status = THREAD_BLOCKED;
242 /* Idle thread. Executes when no other thread is ready to run. */
244 idle (void *aux UNUSED)
246 idle_thread = thread_current ();
250 /* Let someone else run. */
255 /* Use CPU `hlt' instruction to wait for interrupt. */
260 /* Function used as the basis for a kernel thread. */
262 kernel_thread (thread_func *function, void *aux)
264 ASSERT (function != NULL);
266 intr_enable (); /* The scheduler runs with interrupts off. */
267 function (aux); /* Execute the thread function. */
268 thread_exit (); /* If function() returns, kill the thread. */
271 /* Returns the running thread. */
273 running_thread (void)
277 /* Copy the CPU's stack pointer into `esp', and then round that
278 down to the start of a page. Because `struct thread' is
279 always at the beginning of a page and the stack pointer is
280 somewhere in the middle, this locates the curent thread. */
281 asm ("movl %%esp, %0\n" : "=g" (esp));
282 return pg_round_down (esp);
285 /* Returns true if T appears to point to a valid thread. */
287 is_thread (struct thread *t)
289 return t != NULL && t->magic == THREAD_MAGIC;
292 /* Does basic initialization of T as a blocked thread named
295 init_thread (struct thread *t, const char *name, int priority)
298 ASSERT (PRI_MIN <= priority && priority <= PRI_MAX);
299 ASSERT (name != NULL);
301 memset (t, 0, sizeof *t);
302 t->status = THREAD_BLOCKED;
303 strlcpy (t->name, name, sizeof t->name);
304 t->stack = (uint8_t *) t + PGSIZE;
305 t->priority = priority;
306 t->magic = THREAD_MAGIC;
309 /* Allocates a SIZE-byte frame at the top of thread T's stack and
310 returns a pointer to the frame's base. */
312 alloc_frame (struct thread *t, size_t size)
314 /* Stack data is always allocated in word-size units. */
315 ASSERT (is_thread (t));
316 ASSERT (size % sizeof (uint32_t) == 0);
322 /* Chooses and returns the next thread to be scheduled. Should
323 return a thread from the run queue, unless the run queue is
324 empty. (If the running thread can continue running, then it
325 will be in the run queue.) If the run queue is empty, return
327 static struct thread *
328 next_thread_to_run (void)
330 if (list_empty (&ready_list))
333 return list_entry (list_pop_front (&ready_list), struct thread, elem);
336 /* Destroys T, which must not be the running thread. */
338 destroy_thread (struct thread *t)
340 ASSERT (is_thread (t));
341 ASSERT (t != thread_current ());
346 if (t != initial_thread)
350 /* Completes a thread switch by activating the new thread's page
351 tables, and, if the previous thread is dying, destroying it.
353 At this function's invocation, we just switched from thread
354 PREV, the new thread is already running, and interrupts are
355 still disabled. This function is normally invoked by
356 thread_schedule() as its final action before returning, but
357 the first time a thread is scheduled it is called by
358 switch_entry() (see switch.S).
360 After this function and its caller returns, the thread switch
363 schedule_tail (struct thread *prev)
365 struct thread *cur = running_thread ();
367 ASSERT (intr_get_level () == INTR_OFF);
369 /* Mark us as running. */
370 cur->status = THREAD_RUNNING;
373 /* Activate the new address space. */
377 /* If the thread we switched from is dying, destroy it.
378 This must happen late because it's not a good idea to
379 e.g. destroy the page table you're currently using. */
380 if (prev != NULL && prev->status == THREAD_DYING)
381 destroy_thread (prev);
384 /* Schedules a new process. At entry, interrupts must be off and
385 the running process's state must have been changed from
386 running to some other state. This function finds another
387 thread to run and switches to it. */
391 struct thread *cur = running_thread ();
392 struct thread *next = next_thread_to_run ();
393 struct thread *prev = NULL;
395 ASSERT (intr_get_level () == INTR_OFF);
396 ASSERT (cur->status != THREAD_RUNNING);
397 ASSERT (is_thread (next));
400 prev = switch_threads (cur, next);
401 schedule_tail (prev);
404 /* Returns a tid to use for a new thread. */
408 static tid_t next_tid = 1;
411 lock_acquire (&tid_lock);
413 lock_release (&tid_lock);
418 /* Offset of `stack' member within `struct thread'.
419 Used by switch.S, which can't figure it out on its own. */
420 uint32_t thread_stack_ofs = offsetof (struct thread, stack);