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 +}