5 #include "intr-stubs.h"
12 /* Offset of `stack' member within `struct thread'.
13 Used by switch.S, which can't figure it out on its own. */
14 uint32_t thread_stack_ofs = offsetof (struct thread, stack);
16 /* List of processes in THREAD_READY state,
17 that is, processes that are ready to run but not actually
19 static struct list run_queue;
21 /* Thread to run when nothing else is ready. */
22 static struct thread *idle_thread;
24 /* Idle thread. Executes when no other thread is ready to run. */
26 idle (void *aux UNUSED)
30 /* Wait for an interrupt. */
33 /* Let someone else run. */
40 /* Initializes the threading system and starts an initial thread
41 which is immediately scheduled. Never returns to the caller.
42 The initial thread is named NAME and executes FUNCTION passing
43 AUX as the argument. */
45 thread_init (const char *name, void (*function) (void *aux), void *aux)
47 struct thread *initial_thread;
49 ASSERT (intr_get_level () == IF_OFF);
51 /* Initialize run queue. */
52 list_init (&run_queue);
54 /* Create idle thread. */
55 idle_thread = thread_create ("idle", idle, NULL);
56 idle_thread->status = THREAD_BLOCKED;
58 /* Create initial thread and switch to it. */
59 initial_thread = thread_create (name, function, aux);
60 list_remove (&initial_thread->rq_elem);
61 initial_thread->status = THREAD_RUNNING;
62 switch_threads (NULL, initial_thread);
67 /* Stack frame for kernel_thread(). */
68 struct kernel_thread_frame
70 void *eip; /* Return address. */
71 void (*function) (void *); /* Function to call. */
72 void *aux; /* Auxiliary data for function. */
75 /* Function used as the basis for a kernel thread. */
77 kernel_thread (void (*function) (void *aux), void *aux)
79 ASSERT (function != NULL);
81 intr_enable (); /* The scheduler runs with interrupts off. */
82 function (aux); /* Execute the thread function. */
83 thread_exit (); /* If function() returns, kill the thread. */
86 /* Creates a new thread named NAME and initializes its fields.
87 Returns the new thread if successful or a null pointer on
89 static struct thread *
90 new_thread (const char *name)
94 ASSERT (name != NULL);
96 t = palloc_get (PAL_ZERO);
99 strlcpy (t->name, name, sizeof t->name);
100 t->stack = (uint8_t *) t + PGSIZE;
101 t->status = THREAD_INITIALIZING;
107 /* Allocates a SIZE-byte frame within thread T's stack and
108 returns a pointer to the frame's base. */
110 alloc_frame (struct thread *t, size_t size)
112 /* Stack data is always allocated in word-size units. */
113 ASSERT (size % sizeof (uint32_t) == 0);
119 /* Creates a new kernel thread named NAME, which executes
120 FUNCTION passing AUX as the argument. The thread is added to
121 the ready queue. Thus, it may be scheduled even before
122 thread_create() returns. If you need to ensure ordering, then
123 use synchronization, such as a semaphore. */
125 thread_create (const char *name, void (*function) (void *aux), void *aux)
128 struct kernel_thread_frame *kf;
129 struct switch_entry_frame *ef;
130 struct switch_threads_frame *sf;
132 ASSERT (function != NULL);
134 t = new_thread (name);
136 /* Stack frame for kernel_thread(). */
137 kf = alloc_frame (t, sizeof *kf);
139 kf->function = function;
142 /* Stack frame for switch_entry(). */
143 ef = alloc_frame (t, sizeof *ef);
144 ef->eip = (void (*) (void)) kernel_thread;
146 /* Stack frame for switch_threads(). */
147 sf = alloc_frame (t, sizeof *sf);
148 sf->eip = switch_entry;
150 /* Add to run queue. */
157 thread_current (void)
160 asm ("movl %%esp, %0\n" : "=g" (esp));
161 return pg_round_down (esp);
166 thread_execute (const char *filename)
169 struct intr_frame *if_;
170 struct switch_entry_frame *ef;
171 struct switch_threads_frame *sf;
172 void (*start) (void);
174 ASSERT (filename != NULL);
176 t = new_thread (filename);
180 if (!addrspace_load (&t->addrspace, filename, &start))
181 panic ("%s: program load failed", filename);
183 /* Interrupt frame. */
184 if_ = alloc_frame (t, sizeof *if_);
189 if_->eflags = FLAG_IF | 2;
190 if_->esp = PHYS_BASE;
193 /* Stack frame for switch_entry(). */
194 ef = alloc_frame (t, sizeof *ef);
197 /* Stack frame for switch_threads(). */
198 sf = alloc_frame (t, sizeof *sf);
199 sf->eip = switch_entry;
201 /* Add to run queue. */
209 thread_ready (struct thread *t)
211 if (t->status != THREAD_READY)
213 list_push_back (&run_queue, &t->rq_elem);
214 t->status = THREAD_READY;
218 static struct thread *
219 find_next_to_run (void)
221 if (list_empty (&run_queue))
224 return list_entry (list_pop_front (&run_queue), struct thread, rq_elem);
228 thread_destroy (struct thread *t)
230 ASSERT (t->status == THREAD_DYING);
231 ASSERT (t != thread_current ());
236 void schedule_tail (struct thread *prev);
239 schedule_tail (struct thread *prev)
241 ASSERT (intr_get_level () == IF_OFF);
244 addrspace_activate (&thread_current ()->addrspace);
247 if (prev != NULL && prev->status == THREAD_DYING)
248 thread_destroy (prev);
252 thread_schedule (void)
254 struct thread *cur, *next, *prev;
256 ASSERT (intr_get_level () == IF_OFF);
258 cur = thread_current ();
259 ASSERT (cur->status != THREAD_RUNNING);
261 next = find_next_to_run ();
265 next->status = THREAD_RUNNING;
268 prev = switch_threads (cur, next);
270 /* Prevent GCC from reordering anything around the thread
272 asm volatile ("" : : : "memory");
274 schedule_tail (prev);
281 enum if_level old_level;
283 ASSERT (!intr_context ());
285 old_level = intr_disable ();
286 thread_ready (thread_current ());
288 intr_set_level (old_level);
294 ASSERT (!intr_context ());
297 thread_current ()->status = THREAD_DYING;
305 ASSERT (!intr_context ());
306 ASSERT (intr_get_level () == IF_OFF);
308 thread_current ()->status = THREAD_BLOCKED;