Initial revision
[pintos-anon] / src / threads / thread.c
1 #include "thread.h"
2 #include <stddef.h>
3 #include "debug.h"
4 #include "interrupt.h"
5 #include "lib.h"
6 #include "mmu.h"
7 #include "palloc.h"
8
9 uint32_t thread_stack_ofs = offsetof (struct thread, stack);
10
11 static struct list run_queue;
12
13 struct thread *thread_switch (struct thread *cur, struct thread *next);
14
15 void
16 thread_init (void) 
17 {
18   list_init (&run_queue);
19 }
20
21 static void
22 thread_root (void (*function) (void *aux), void *aux) 
23 {
24   ASSERT (function != NULL);
25   
26   function (aux);
27   thread_exit ();
28 }
29
30 struct thread *
31 thread_create (const char *name, void (*function) (void *aux), void *aux) 
32 {
33   struct thread *t;
34
35   ASSERT (name != NULL);
36   ASSERT (function != NULL);
37
38   t = palloc_get (0);
39   if (t == NULL)
40     return NULL;
41
42   memset (t, 0, NBPG);
43   strlcpy (t->name, name, sizeof t->name);
44
45   /* Set up stack. */
46   t->stack = (uint32_t *) ((uint8_t *) t + NBPG);
47   *--t->stack = (uint32_t) aux;
48   *--t->stack = (uint32_t) function;
49   --t->stack;
50   *--t->stack = (uint32_t) thread_root;
51   t->stack -= 4;
52
53   /* Add to run_queue. */
54   t->status = THREAD_BLOCKED;
55   thread_ready (t);
56
57   return t;
58 }
59
60 static struct thread *
61 stack_to_thread (uint32_t *stack) 
62 {
63   return (struct thread *) ((uint32_t) (stack - 1) & ~((uint32_t) NBPG - 1));
64 }
65
66 struct thread *
67 thread_current (void) 
68 {
69   uint32_t *esp;
70   asm ("movl %%esp, %0\n" : "=g" (esp));
71   return stack_to_thread (esp);
72 }
73
74 void
75 thread_ready (struct thread *t) 
76 {
77   if (t->status != THREAD_READY) 
78     {
79       list_push_back (&run_queue, &t->rq_elem);
80       t->status = THREAD_READY;
81     }
82 }
83
84 static struct thread *
85 find_next_to_run (void) 
86 {
87   if (list_empty (&run_queue))
88     return NULL;
89   else
90     return list_entry (list_pop_front (&run_queue), struct thread, rq_elem);
91 }
92
93 static void
94 idle (void) 
95 {
96   static int idle = 0;
97   if (idle++ == 0)
98     printk ("idle\n");
99 }
100
101 void
102 thread_destroy (struct thread *t) 
103 {
104   ASSERT (t->status == THREAD_DYING);
105   ASSERT (t != thread_current ());
106
107   palloc_free (t);
108 }
109
110 void
111 thread_schedule (void) 
112 {
113   struct thread *cur, *next, *prev;
114
115   cur = thread_current ();
116   ASSERT (cur->status != THREAD_RUNNING);
117
118   while ((next = find_next_to_run ()) == NULL)
119     idle ();
120
121   next->status = THREAD_RUNNING;
122   prev = thread_switch (cur, next);
123   if (prev != NULL && prev->status == THREAD_DYING) 
124     thread_destroy (prev);
125 }
126
127 void
128 thread_yield (void) 
129 {
130   ASSERT (!intr_context ());
131   thread_ready (thread_current ());
132   thread_schedule ();
133 }
134
135 void
136 thread_start (struct thread *t) 
137 {
138   if (t->status == THREAD_READY) 
139     list_remove (&t->rq_elem);
140   t->status = THREAD_RUNNING;
141   thread_switch (NULL, t);
142 }
143
144 void
145 thread_exit (void) 
146 {
147   struct thread *t = thread_current ();
148   t->status = THREAD_DYING;
149   thread_schedule ();
150 }
151
152 void
153 thread_sleep (void) 
154 {
155   ASSERT (intr_get_level () == IF_OFF);
156
157   thread_current ()->status = THREAD_BLOCKED;
158   thread_schedule ();
159 }