kern
diff src/sched.c @ 55:88a6c4e192f9
Fixed most important task switching bugs.
Now it seems that I can switch in and out of user space reliably.
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 15 Aug 2011 04:03:39 +0300 |
parents | 23abbeea4d5f |
children | 0be4615594df |
line diff
1.1 --- a/src/sched.c Sun Aug 14 16:57:23 2011 +0300 1.2 +++ b/src/sched.c Mon Aug 15 04:03:39 2011 +0300 1.3 @@ -1,35 +1,36 @@ 1.4 #include <stdio.h> 1.5 +#include <assert.h> 1.6 #include "sched.h" 1.7 #include "proc.h" 1.8 #include "intr.h" 1.9 #include "asmops.h" 1.10 #include "config.h" 1.11 1.12 -#define EMPTY(q) ((q).head == 0) 1.13 +#define EMPTY(q) ((q)->head == 0) 1.14 1.15 struct proc_list { 1.16 struct process *head, *tail; 1.17 }; 1.18 1.19 -static void ins_back(struct proc_list *q, struct process *proc); 1.20 -static void ins_front(struct proc_list *q, struct process *proc); 1.21 -static void remove(struct proc_list *q, struct process *proc); 1.22 +static void idle_proc(void); 1.23 +static void ins_back(struct proc_list *list, struct process *proc); 1.24 +static void ins_front(struct proc_list *list, struct process *proc); 1.25 +static void remove(struct proc_list *list, struct process *proc); 1.26 +static int hash_addr(void *addr); 1.27 1.28 static struct proc_list runq; 1.29 -static struct proc_list waitq; 1.30 static struct proc_list zombieq; 1.31 1.32 +#define HTBL_SIZE 101 1.33 +static struct proc_list wait_htable[HTBL_SIZE]; 1.34 + 1.35 + 1.36 void schedule(void) 1.37 { 1.38 disable_intr(); 1.39 1.40 - if(EMPTY(runq)) { 1.41 - /* idle "process". 1.42 - * make sure interrupts are enabled before halting 1.43 - */ 1.44 - enable_intr(); 1.45 - halt_cpu(); 1.46 - printf("fuck you!\n"); 1.47 + if(EMPTY(&runq)) { 1.48 + idle_proc(); 1.49 /* this won't return, it'll just wake up in an interrupt later */ 1.50 } 1.51 1.52 @@ -47,14 +48,13 @@ 1.53 runq.head->ticks_left = TIMESLICE_TICKS; 1.54 } 1.55 1.56 - /* no need to re-enable interrupts, they will be enabled with the iret */ 1.57 + /* always enter context_switch with interrupts disabled */ 1.58 context_switch(runq.head->id); 1.59 } 1.60 1.61 -int add_proc(int pid, enum proc_state state) 1.62 +void add_proc(int pid) 1.63 { 1.64 int istate; 1.65 - struct proc_list *q; 1.66 struct process *proc; 1.67 1.68 istate = get_intr_state(); 1.69 @@ -62,85 +62,102 @@ 1.70 1.71 proc = get_process(pid); 1.72 1.73 - q = state == STATE_RUNNABLE ? &runq : &waitq; 1.74 - 1.75 - ins_back(q, proc); 1.76 - proc->state = state; 1.77 - 1.78 - set_intr_state(istate); 1.79 - return 0; 1.80 -} 1.81 - 1.82 -int block_proc(int pid) 1.83 -{ 1.84 - int istate; 1.85 - struct process *proc = get_process(pid); 1.86 - 1.87 - if(proc->state != STATE_RUNNABLE) { 1.88 - printf("block_proc: process %d not running\n", pid); 1.89 - return -1; 1.90 - } 1.91 - 1.92 - istate = get_intr_state(); 1.93 - disable_intr(); 1.94 - 1.95 - remove(&runq, proc); 1.96 - ins_back(&waitq, proc); 1.97 - proc->state = STATE_BLOCKED; 1.98 - 1.99 - set_intr_state(istate); 1.100 - return 0; 1.101 -} 1.102 - 1.103 -int unblock_proc(int pid) 1.104 -{ 1.105 - int istate; 1.106 - struct process *proc = get_process(pid); 1.107 - 1.108 - if(proc->state != STATE_BLOCKED) { 1.109 - printf("unblock_proc: process %d not blocked\n", pid); 1.110 - return -1; 1.111 - } 1.112 - 1.113 - istate = get_intr_state(); 1.114 - disable_intr(); 1.115 - 1.116 - remove(&waitq, proc); 1.117 ins_back(&runq, proc); 1.118 proc->state = STATE_RUNNABLE; 1.119 1.120 set_intr_state(istate); 1.121 - return 0; 1.122 } 1.123 1.124 +/* block the process until we get a wakeup call for address ev */ 1.125 +void wait(void *wait_addr) 1.126 +{ 1.127 + struct process *p; 1.128 + int hash_idx; 1.129 1.130 -static void ins_back(struct proc_list *q, struct process *proc) 1.131 + disable_intr(); 1.132 + 1.133 + p = get_current_proc(); 1.134 + assert(p); 1.135 + 1.136 + /* remove it from the runqueue ... */ 1.137 + remove(&runq, p); 1.138 + 1.139 + /* and place it in the wait hash table based on sleep_addr */ 1.140 + hash_idx = hash_addr(wait_addr); 1.141 + ins_back(wait_htable + hash_idx, p); 1.142 + 1.143 + p->state = STATE_BLOCKED; 1.144 + p->wait_addr = wait_addr; 1.145 +} 1.146 + 1.147 +/* wake up all the processes sleeping on this address */ 1.148 +void wakeup(void *wait_addr) 1.149 { 1.150 - if(EMPTY(*q)) { 1.151 - q->head = proc; 1.152 + int hash_idx; 1.153 + struct process *iter; 1.154 + struct proc_list *list; 1.155 + 1.156 + hash_idx = hash_addr(wait_addr); 1.157 + list = wait_htable + hash_idx; 1.158 + 1.159 + iter = list->head; 1.160 + while(iter) { 1.161 + if(iter->wait_addr == wait_addr) { 1.162 + /* found one, remove it, and make it runnable */ 1.163 + struct process *p = iter; 1.164 + iter = iter->next; 1.165 + 1.166 + remove(list, p); 1.167 + p->state = STATE_RUNNABLE; 1.168 + ins_back(&runq, p); 1.169 + } else { 1.170 + iter = iter->next; 1.171 + } 1.172 + } 1.173 +} 1.174 + 1.175 +static void idle_proc(void) 1.176 +{ 1.177 + /* make sure we send any pending EOIs if needed. 1.178 + * end_of_irq will actually check if it's needed first. 1.179 + */ 1.180 + struct intr_frame *ifrm = get_intr_frame(); 1.181 + end_of_irq(INTR_TO_IRQ(ifrm->inum)); 1.182 + 1.183 + /* make sure interrupts are enabled before halting */ 1.184 + enable_intr(); 1.185 + halt_cpu(); 1.186 +} 1.187 + 1.188 + 1.189 +/* list operations */ 1.190 +static void ins_back(struct proc_list *list, struct process *proc) 1.191 +{ 1.192 + if(EMPTY(list)) { 1.193 + list->head = proc; 1.194 } else { 1.195 - q->tail->next = proc; 1.196 + list->tail->next = proc; 1.197 } 1.198 1.199 proc->next = 0; 1.200 - proc->prev = q->tail; 1.201 - q->tail = proc; 1.202 + proc->prev = list->tail; 1.203 + list->tail = proc; 1.204 } 1.205 1.206 -static void ins_front(struct proc_list *q, struct process *proc) 1.207 +static void ins_front(struct proc_list *list, struct process *proc) 1.208 { 1.209 - if(EMPTY(*q)) { 1.210 - q->tail = proc; 1.211 + if(EMPTY(list)) { 1.212 + list->tail = proc; 1.213 } else { 1.214 - q->head->prev = proc; 1.215 + list->head->prev = proc; 1.216 } 1.217 1.218 - proc->next = q->head; 1.219 + proc->next = list->head; 1.220 proc->prev = 0; 1.221 - q->head = proc; 1.222 + list->head = proc; 1.223 } 1.224 1.225 -static void remove(struct proc_list *q, struct process *proc) 1.226 +static void remove(struct proc_list *list, struct process *proc) 1.227 { 1.228 if(proc->prev) { 1.229 proc->prev->next = proc->next; 1.230 @@ -148,10 +165,15 @@ 1.231 if(proc->next) { 1.232 proc->next->prev = proc->prev; 1.233 } 1.234 - if(q->head == proc) { 1.235 - q->head = proc->next; 1.236 + if(list->head == proc) { 1.237 + list->head = proc->next; 1.238 } 1.239 - if(q->tail == proc) { 1.240 - q->tail = proc->prev; 1.241 + if(list->tail == proc) { 1.242 + list->tail = proc->prev; 1.243 } 1.244 } 1.245 + 1.246 +static int hash_addr(void *addr) 1.247 +{ 1.248 + return (uint32_t)addr % HTBL_SIZE; 1.249 +}