rev |
line source |
nuclear@51
|
1 #include <stdio.h>
|
nuclear@55
|
2 #include <assert.h>
|
nuclear@51
|
3 #include "sched.h"
|
nuclear@51
|
4 #include "proc.h"
|
nuclear@51
|
5 #include "intr.h"
|
nuclear@51
|
6 #include "asmops.h"
|
nuclear@51
|
7 #include "config.h"
|
nuclear@51
|
8
|
nuclear@55
|
9 #define EMPTY(q) ((q)->head == 0)
|
nuclear@51
|
10
|
nuclear@51
|
11 struct proc_list {
|
nuclear@51
|
12 struct process *head, *tail;
|
nuclear@51
|
13 };
|
nuclear@51
|
14
|
nuclear@55
|
15 static void idle_proc(void);
|
nuclear@55
|
16 static void ins_back(struct proc_list *list, struct process *proc);
|
nuclear@55
|
17 static void ins_front(struct proc_list *list, struct process *proc);
|
nuclear@55
|
18 static void remove(struct proc_list *list, struct process *proc);
|
nuclear@55
|
19 static int hash_addr(void *addr);
|
nuclear@51
|
20
|
nuclear@51
|
21 static struct proc_list runq;
|
nuclear@51
|
22 static struct proc_list zombieq;
|
nuclear@51
|
23
|
nuclear@55
|
24 #define HTBL_SIZE 101
|
nuclear@55
|
25 static struct proc_list wait_htable[HTBL_SIZE];
|
nuclear@55
|
26
|
nuclear@55
|
27
|
nuclear@51
|
28 void schedule(void)
|
nuclear@51
|
29 {
|
nuclear@52
|
30 disable_intr();
|
nuclear@52
|
31
|
nuclear@55
|
32 if(EMPTY(&runq)) {
|
nuclear@56
|
33 if(!get_current_proc()) {
|
nuclear@56
|
34 /* we're already in the idle process, don't reenter it
|
nuclear@56
|
35 * or you'll fill up the stack very quickly.
|
nuclear@56
|
36 */
|
nuclear@56
|
37 return;
|
nuclear@56
|
38 }
|
nuclear@56
|
39
|
nuclear@55
|
40 idle_proc();
|
nuclear@56
|
41 return;
|
nuclear@51
|
42 }
|
nuclear@51
|
43
|
nuclear@51
|
44 /* if the current process exhausted its timeslice,
|
nuclear@51
|
45 * move it to the back of the queue.
|
nuclear@51
|
46 */
|
nuclear@51
|
47 if(runq.head->ticks_left <= 0) {
|
nuclear@51
|
48 if(runq.head->next) {
|
nuclear@51
|
49 struct process *proc = runq.head;
|
nuclear@51
|
50 remove(&runq, proc);
|
nuclear@51
|
51 ins_back(&runq, proc);
|
nuclear@51
|
52 }
|
nuclear@51
|
53
|
nuclear@51
|
54 /* start a new timeslice */
|
nuclear@51
|
55 runq.head->ticks_left = TIMESLICE_TICKS;
|
nuclear@51
|
56 }
|
nuclear@51
|
57
|
nuclear@55
|
58 /* always enter context_switch with interrupts disabled */
|
nuclear@51
|
59 context_switch(runq.head->id);
|
nuclear@51
|
60 }
|
nuclear@51
|
61
|
nuclear@55
|
62 void add_proc(int pid)
|
nuclear@51
|
63 {
|
nuclear@51
|
64 int istate;
|
nuclear@52
|
65 struct process *proc;
|
nuclear@51
|
66
|
nuclear@51
|
67 istate = get_intr_state();
|
nuclear@51
|
68 disable_intr();
|
nuclear@51
|
69
|
nuclear@52
|
70 proc = get_process(pid);
|
nuclear@52
|
71
|
nuclear@51
|
72 ins_back(&runq, proc);
|
nuclear@53
|
73 proc->state = STATE_RUNNABLE;
|
nuclear@51
|
74
|
nuclear@51
|
75 set_intr_state(istate);
|
nuclear@51
|
76 }
|
nuclear@51
|
77
|
nuclear@72
|
78 void remove_proc(int pid)
|
nuclear@72
|
79 {
|
nuclear@72
|
80 int istate;
|
nuclear@72
|
81 struct process *proc;
|
nuclear@72
|
82
|
nuclear@72
|
83 istate = get_intr_state();
|
nuclear@72
|
84 disable_intr();
|
nuclear@72
|
85
|
nuclear@72
|
86 proc = get_process(pid);
|
nuclear@72
|
87 remove(&runq, proc);
|
nuclear@72
|
88
|
nuclear@72
|
89 set_intr_state(istate);
|
nuclear@72
|
90 }
|
nuclear@72
|
91
|
nuclear@55
|
92 /* block the process until we get a wakeup call for address ev */
|
nuclear@55
|
93 void wait(void *wait_addr)
|
nuclear@55
|
94 {
|
nuclear@55
|
95 struct process *p;
|
nuclear@55
|
96 int hash_idx;
|
nuclear@51
|
97
|
nuclear@55
|
98 disable_intr();
|
nuclear@55
|
99
|
nuclear@55
|
100 p = get_current_proc();
|
nuclear@55
|
101 assert(p);
|
nuclear@55
|
102
|
nuclear@55
|
103 /* remove it from the runqueue ... */
|
nuclear@55
|
104 remove(&runq, p);
|
nuclear@55
|
105
|
nuclear@55
|
106 /* and place it in the wait hash table based on sleep_addr */
|
nuclear@55
|
107 hash_idx = hash_addr(wait_addr);
|
nuclear@55
|
108 ins_back(wait_htable + hash_idx, p);
|
nuclear@55
|
109
|
nuclear@55
|
110 p->state = STATE_BLOCKED;
|
nuclear@55
|
111 p->wait_addr = wait_addr;
|
nuclear@56
|
112
|
nuclear@56
|
113 /* call the scheduler to give time to another process */
|
nuclear@56
|
114 schedule();
|
nuclear@55
|
115 }
|
nuclear@55
|
116
|
nuclear@55
|
117 /* wake up all the processes sleeping on this address */
|
nuclear@55
|
118 void wakeup(void *wait_addr)
|
nuclear@51
|
119 {
|
nuclear@55
|
120 int hash_idx;
|
nuclear@55
|
121 struct process *iter;
|
nuclear@55
|
122 struct proc_list *list;
|
nuclear@55
|
123
|
nuclear@55
|
124 hash_idx = hash_addr(wait_addr);
|
nuclear@55
|
125 list = wait_htable + hash_idx;
|
nuclear@55
|
126
|
nuclear@55
|
127 iter = list->head;
|
nuclear@55
|
128 while(iter) {
|
nuclear@55
|
129 if(iter->wait_addr == wait_addr) {
|
nuclear@55
|
130 /* found one, remove it, and make it runnable */
|
nuclear@55
|
131 struct process *p = iter;
|
nuclear@55
|
132 iter = iter->next;
|
nuclear@55
|
133
|
nuclear@55
|
134 remove(list, p);
|
nuclear@55
|
135 p->state = STATE_RUNNABLE;
|
nuclear@55
|
136 ins_back(&runq, p);
|
nuclear@55
|
137 } else {
|
nuclear@55
|
138 iter = iter->next;
|
nuclear@55
|
139 }
|
nuclear@55
|
140 }
|
nuclear@55
|
141 }
|
nuclear@55
|
142
|
nuclear@55
|
143 static void idle_proc(void)
|
nuclear@55
|
144 {
|
nuclear@55
|
145 /* make sure we send any pending EOIs if needed.
|
nuclear@55
|
146 * end_of_irq will actually check if it's needed first.
|
nuclear@55
|
147 */
|
nuclear@55
|
148 struct intr_frame *ifrm = get_intr_frame();
|
nuclear@55
|
149 end_of_irq(INTR_TO_IRQ(ifrm->inum));
|
nuclear@55
|
150
|
nuclear@56
|
151 set_current_pid(0);
|
nuclear@56
|
152
|
nuclear@57
|
153 printf("idle loop is running\n");
|
nuclear@57
|
154
|
nuclear@55
|
155 /* make sure interrupts are enabled before halting */
|
nuclear@56
|
156 while(EMPTY(&runq)) {
|
nuclear@56
|
157 enable_intr();
|
nuclear@56
|
158 halt_cpu();
|
nuclear@56
|
159 disable_intr();
|
nuclear@56
|
160 }
|
nuclear@55
|
161 }
|
nuclear@55
|
162
|
nuclear@55
|
163
|
nuclear@55
|
164 /* list operations */
|
nuclear@55
|
165 static void ins_back(struct proc_list *list, struct process *proc)
|
nuclear@55
|
166 {
|
nuclear@55
|
167 if(EMPTY(list)) {
|
nuclear@55
|
168 list->head = proc;
|
nuclear@51
|
169 } else {
|
nuclear@55
|
170 list->tail->next = proc;
|
nuclear@51
|
171 }
|
nuclear@51
|
172
|
nuclear@51
|
173 proc->next = 0;
|
nuclear@55
|
174 proc->prev = list->tail;
|
nuclear@55
|
175 list->tail = proc;
|
nuclear@51
|
176 }
|
nuclear@51
|
177
|
nuclear@55
|
178 static void ins_front(struct proc_list *list, struct process *proc)
|
nuclear@51
|
179 {
|
nuclear@55
|
180 if(EMPTY(list)) {
|
nuclear@55
|
181 list->tail = proc;
|
nuclear@51
|
182 } else {
|
nuclear@55
|
183 list->head->prev = proc;
|
nuclear@51
|
184 }
|
nuclear@51
|
185
|
nuclear@55
|
186 proc->next = list->head;
|
nuclear@51
|
187 proc->prev = 0;
|
nuclear@55
|
188 list->head = proc;
|
nuclear@51
|
189 }
|
nuclear@51
|
190
|
nuclear@55
|
191 static void remove(struct proc_list *list, struct process *proc)
|
nuclear@51
|
192 {
|
nuclear@51
|
193 if(proc->prev) {
|
nuclear@51
|
194 proc->prev->next = proc->next;
|
nuclear@51
|
195 }
|
nuclear@51
|
196 if(proc->next) {
|
nuclear@51
|
197 proc->next->prev = proc->prev;
|
nuclear@51
|
198 }
|
nuclear@55
|
199 if(list->head == proc) {
|
nuclear@55
|
200 list->head = proc->next;
|
nuclear@51
|
201 }
|
nuclear@55
|
202 if(list->tail == proc) {
|
nuclear@55
|
203 list->tail = proc->prev;
|
nuclear@51
|
204 }
|
nuclear@51
|
205 }
|
nuclear@55
|
206
|
nuclear@55
|
207 static int hash_addr(void *addr)
|
nuclear@55
|
208 {
|
nuclear@55
|
209 return (uint32_t)addr % HTBL_SIZE;
|
nuclear@55
|
210 }
|