Cleanup.
[pintos-anon] / src / threads / thread.c
1 #include "threads/thread.h"
2 #include <debug.h>
3 #include <stddef.h>
4 #include <random.h>
5 #include <stdio.h>
6 #include <string.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"
14 #ifdef USERPROG
15 #include "userprog/process.h"
16 #endif
17
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
22
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;
26
27 /* Idle thread. */
28 static struct thread *idle_thread;
29
30 /* Initial thread, the thread running init.c:main(). */
31 static struct thread *initial_thread;
32
33 /* Lock used by allocate_tid(). */
34 static struct lock tid_lock;
35
36 /* Stack frame for kernel_thread(). */
37 struct kernel_thread_frame 
38   {
39     void *eip;                  /* Return address. */
40     thread_func *function;      /* Function to call. */
41     void *aux;                  /* Auxiliary data for function. */
42   };
43
44 static void kernel_thread (thread_func *, void *aux);
45
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);
56
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.
62
63    After calling this function, be sure to initialize the page
64    allocator before trying to create any threads with
65    thread_create(). */
66 void
67 thread_init (void) 
68 {
69   ASSERT (intr_get_level () == INTR_OFF);
70
71   lock_init (&tid_lock, "tid");
72   list_init (&ready_list);
73
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 ();
79 }
80
81 /* Starts preemptive thread scheduling by enabling interrupts.
82    Also creates the idle thread. */
83 void
84 thread_start (void) 
85 {
86   thread_create ("idle", PRI_DEFAULT, idle, NULL);
87   intr_enable ();
88 }
89
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
98    creation fails.
99
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. */
103 tid_t
104 thread_create (const char *name, int priority,
105                thread_func *function, void *aux) 
106 {
107   struct thread *t;
108   struct kernel_thread_frame *kf;
109   struct switch_entry_frame *ef;
110   struct switch_threads_frame *sf;
111   tid_t tid;
112
113   ASSERT (function != NULL);
114
115   /* Allocate thread. */
116   t = palloc_get (PAL_ZERO);
117   if (t == NULL)
118     return TID_ERROR;
119
120   /* Initialize thread. */
121   init_thread (t, name, priority);
122   tid = t->tid = allocate_tid ();
123
124   /* Stack frame for kernel_thread(). */
125   kf = alloc_frame (t, sizeof *kf);
126   kf->eip = NULL;
127   kf->function = function;
128   kf->aux = aux;
129
130   /* Stack frame for switch_entry(). */
131   ef = alloc_frame (t, sizeof *ef);
132   ef->eip = (void (*) (void)) kernel_thread;
133
134   /* Stack frame for switch_threads(). */
135   sf = alloc_frame (t, sizeof *sf);
136   sf->eip = switch_entry;
137
138   /* Add to run queue. */
139   thread_unblock (t);
140
141   return tid;
142 }
143
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.) */
147 void
148 thread_unblock (struct thread *t) 
149 {
150   enum intr_level old_level;
151
152   ASSERT (is_thread (t));
153
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);
159 }
160
161 /* Returns the name of the running thread. */
162 const char *
163 thread_name (void) 
164 {
165   return thread_current ()->name;
166 }
167
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. */
171 struct thread *
172 thread_current (void) 
173 {
174   struct thread *t = running_thread ();
175   
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);
183
184   return t;
185 }
186
187 /* Returns the running thread's tid. */
188 tid_t
189 thread_tid (void) 
190 {
191   return thread_current ()->tid;
192 }
193
194 /* Deschedules the current thread and destroys it.  Never
195    returns to the caller. */
196 void
197 thread_exit (void) 
198 {
199   ASSERT (!intr_context ());
200
201   /* Just set our status to dying and schedule another process.
202      We will be destroyed during the call to schedule_tail(). */
203   intr_disable ();
204   thread_current ()->status = THREAD_DYING;
205   schedule ();
206   NOT_REACHED ();
207 }
208
209 /* Yields the CPU.  The current thread is not put to sleep and
210    may be scheduled again immediately at the scheduler's whim. */
211 void
212 thread_yield (void) 
213 {
214   struct thread *cur = thread_current ();
215   enum intr_level old_level;
216   
217   ASSERT (!intr_context ());
218
219   old_level = intr_disable ();
220   list_push_back (&ready_list, &cur->elem);
221   cur->status = THREAD_READY;
222   schedule ();
223   intr_set_level (old_level);
224 }
225
226 /* Puts the current thread to sleep.  It will not be scheduled
227    again until awoken by thread_unblock().
228
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. */
232 void
233 thread_block (void) 
234 {
235   ASSERT (!intr_context ());
236   ASSERT (intr_get_level () == INTR_OFF);
237
238   thread_current ()->status = THREAD_BLOCKED;
239   schedule ();
240 }
241 \f
242 /* Idle thread.  Executes when no other thread is ready to run. */
243 static void
244 idle (void *aux UNUSED) 
245 {
246   idle_thread = thread_current ();
247
248   for (;;) 
249     {
250       /* Let someone else run. */
251       intr_disable ();
252       thread_block ();
253       intr_enable ();
254
255       /* Use CPU `hlt' instruction to wait for interrupt. */
256       asm ("hlt");
257     }
258 }
259
260 /* Function used as the basis for a kernel thread. */
261 static void
262 kernel_thread (thread_func *function, void *aux) 
263 {
264   ASSERT (function != NULL);
265
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. */
269 }
270 \f
271 /* Returns the running thread. */
272 struct thread *
273 running_thread (void) 
274 {
275   uint32_t *esp;
276
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);
283 }
284
285 /* Returns true if T appears to point to a valid thread. */
286 static bool
287 is_thread (struct thread *t) 
288 {
289   return t != NULL && t->magic == THREAD_MAGIC;
290 }
291
292 /* Does basic initialization of T as a blocked thread named
293    NAME. */
294 static void
295 init_thread (struct thread *t, const char *name, int priority)
296 {
297   ASSERT (t != NULL);
298   ASSERT (PRI_MIN <= priority && priority <= PRI_MAX);
299   ASSERT (name != NULL);
300
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;
307 }
308
309 /* Allocates a SIZE-byte frame at the top of thread T's stack and
310    returns a pointer to the frame's base. */
311 static void *
312 alloc_frame (struct thread *t, size_t size) 
313 {
314   /* Stack data is always allocated in word-size units. */
315   ASSERT (is_thread (t));
316   ASSERT (size % sizeof (uint32_t) == 0);
317
318   t->stack -= size;
319   return t->stack;
320 }
321
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
326    idle_thread. */
327 static struct thread *
328 next_thread_to_run (void) 
329 {
330   if (list_empty (&ready_list))
331     return idle_thread;
332   else
333     return list_entry (list_pop_front (&ready_list), struct thread, elem);
334 }
335
336 /* Destroys T, which must not be the running thread. */
337 static void
338 destroy_thread (struct thread *t) 
339 {
340   ASSERT (is_thread (t));
341   ASSERT (t != thread_current ());
342
343 #ifdef USERPROG
344   process_destroy (t);
345 #endif
346   if (t != initial_thread)
347     palloc_free (t);
348 }
349
350 /* Completes a thread switch by activating the new thread's page
351    tables, and, if the previous thread is dying, destroying it.
352
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).
359
360    After this function and its caller returns, the thread switch
361    is complete. */
362 void
363 schedule_tail (struct thread *prev) 
364 {
365   struct thread *cur = running_thread ();
366   
367   ASSERT (intr_get_level () == INTR_OFF);
368
369   /* Mark us as running. */
370   cur->status = THREAD_RUNNING;
371
372 #ifdef USERPROG
373   /* Activate the new address space. */
374   process_activate ();
375 #endif
376
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);
382 }
383
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. */
388 static void
389 schedule (void) 
390 {
391   struct thread *cur = running_thread ();
392   struct thread *next = next_thread_to_run ();
393   struct thread *prev = NULL;
394
395   ASSERT (intr_get_level () == INTR_OFF);
396   ASSERT (cur->status != THREAD_RUNNING);
397   ASSERT (is_thread (next));
398
399   if (cur != next)
400     prev = switch_threads (cur, next);
401   schedule_tail (prev); 
402 }
403
404 /* Returns a tid to use for a new thread. */
405 static tid_t
406 allocate_tid (void) 
407 {
408   static tid_t next_tid = 1;
409   tid_t tid;
410
411   lock_acquire (&tid_lock);
412   tid = next_tid++;
413   lock_release (&tid_lock);
414
415   return tid;
416 }
417 \f
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);