kern

annotate src/sched.c @ 72:3941e82b07f2

- implemented syscalls: exit, waitpid, getppid - moved sys_whatever functions out of syscall.c into more reasonable files - putting all the definitions that must be synced with userland to include/kdef.h
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 15 Oct 2011 07:45:56 +0300
parents 437360696883
children
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 }