1 /* 2 * linux/kernel/sched.c 3 * 4 * (C) 1991 Linus Torvalds 5 */ 6 7 /* 8 * 'sched.c' is the main kernel file. It contains scheduling primitives 9 * (sleep_on, wakeup, schedule etc) as well as a number of simple system 10 * call functions (type getpid(), which just extracts a field from 11 * current-task 12 */ 13 #include <linux/sched.h> 14 #include <linux/kernel.h> 15 #include <linux/sys.h> 16 #include <linux/fdreg.h> 17 #include <asm/system.h> 18 #include <asm/io.h> 19 #include <asm/segment.h> 20 21 #include <signal.h> 22 23 #define _S(nr) (1<<((nr)-1)) 24 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) 25 26 void show_task(int nr,struct task_struct * p) 27 { 28 int i,j = 4096-sizeof(struct task_struct); 29 30 printk("%d: pid=%d, state=%d, ",nr,p->pid,p->state); 31 i=0; 32 while (i<j && !((char *)(p+1))[i]) 33 i++; 34 printk("%d (of %d) chars free in kernel stack ",i,j); 35 } 36 37 void show_stat(void) 38 { 39 int i; 40 41 for (i=0;i<NR_TASKS;i++) 42 if (task[i]) 43 show_task(i,task[i]); 44 } 45 46 #define LATCH (1193180/HZ) 47 48 extern void mem_use(void); 49 50 extern int timer_interrupt(void); 51 extern int system_call(void); 52 53 union task_union { 54 struct task_struct task; 55 char stack[PAGE_SIZE]; 56 }; 57 58 static union task_union init_task = {INIT_TASK,}; 59 60 long volatile jiffies=0; 61 long startup_time=0; 62 struct task_struct *current = &(init_task.task); 63 struct task_struct *last_task_used_math = NULL; 64 65 struct task_struct * task[NR_TASKS] = {&(init_task.task), }; 66 67 long user_stack [ PAGE_SIZE>>2 ] ; 68 69 struct { 70 long * a; 71 short b; 72 } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 }; 73 /* 74 * 'math_state_restore()' saves the current math information in the 75 * old math state array, and gets the new ones from the current task 76 */ 77 void math_state_restore() 78 { 79 if (last_task_used_math == current) 80 return; 81 __asm__("fwait"); 82 if (last_task_used_math) { 83 __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387)); 84 } 85 last_task_used_math=current; 86 if (current->used_math) { 87 __asm__("frstor %0"::"m" (current->tss.i387)); 88 } else { 89 __asm__("fninit"::); 90 current->used_math=1; 91 } 92 } 93 94 /* 95 * 'schedule()' is the scheduler function. This is GOOD CODE! There 96 * probably won't be any reason to change this, as it should work well 97 * in all circumstances (ie gives IO-bound processes good response etc). 98 * The one thing you might take a look at is the signal-handler code here. 99 * 100 * NOTE!! Task 0 is the 'idle' task, which gets called when no other 101 * tasks can run. It can not be killed, and it cannot sleep. The 'state' 102 * information in task[0] is never used. 103 */ 104 void schedule(void) 105 { 106 int i,next,c; 107 struct task_struct ** p; 108 109 /* check alarm, wake up any interruptible tasks that have got a signal */ 110 111 for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) 112 if (*p) { 113 if ((*p)->alarm && (*p)->alarm < jiffies) { 114 (*p)->signal |= (1<<(SIGALRM-1)); 115 (*p)->alarm = 0; 116 } 117 if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) && 118 (*p)->state==TASK_INTERRUPTIBLE) 119 (*p)->state=TASK_RUNNING; 120 } 121 122 /* this is the scheduler proper: */ 123 124 while (1) { 125 c = -1; 126 next = 0; 127 i = NR_TASKS; 128 p = &task[NR_TASKS]; 129 while (--i) { 130 if (!*--p) 131 continue; 132 if ((*p)->state == TASK_RUNNING && (*p)->counter > c) 133 c = (*p)->counter, next = i; 134 } 135 if (c) break; 136 for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) 137 if (*p) 138 (*p)->counter = ((*p)->counter >> 1) + 139 (*p)->priority; 140 } 141 switch_to(next); 142 } 143 144 int sys_pause(void) 145 { 146 current->state = TASK_INTERRUPTIBLE; 147 schedule(); 148 return 0; 149 } 150 151 void sleep_on(struct task_struct **p) 152 { 153 struct task_struct *tmp; 154 155 if (!p) 156 return; 157 if (current == &(init_task.task)) 158 panic("task[0] trying to sleep"); 159 tmp = *p; 160 *p = current; 161 current->state = TASK_UNINTERRUPTIBLE; 162 schedule(); 163 if (tmp) 164 tmp->state=0; 165 } 166 167 void interruptible_sleep_on(struct task_struct **p) 168 { 169 struct task_struct *tmp; 170 171 if (!p) 172 return; 173 if (current == &(init_task.task)) 174 panic("task[0] trying to sleep"); 175 tmp=*p; 176 *p=current; 177 repeat: current->state = TASK_INTERRUPTIBLE; 178 schedule(); 179 if (*p && *p != current) { 180 (**p).state=0; 181 goto repeat; 182 } 183 *p=NULL; 184 if (tmp) 185 tmp->state=0; 186 } 187 188 void wake_up(struct task_struct **p) 189 { 190 if (p && *p) { 191 (**p).state=0; 192 *p=NULL; 193 } 194 } 195 196 /* 197 * OK, here are some floppy things that shouldn't be in the kernel 198 * proper. They are here because the floppy needs a timer, and this 199 * was the easiest way of doing it. 200 */ 201 static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL}; 202 static int mon_timer[4]={0,0,0,0}; 203 static int moff_timer[4]={0,0,0,0}; 204 unsigned char current_DOR = 0x0C; 205 206 int ticks_to_floppy_on(unsigned int nr) 207 { 208 extern unsigned char selected; 209 unsigned char mask = 0x10 << nr; 210 211 if (nr>3) 212 panic("floppy_on: nr>3"); 213 moff_timer[nr]=10000; /* 100 s = very big :-) */ 214 cli(); /* use floppy_off to turn it off */ 215 mask |= current_DOR; 216 if (!selected) { 217 mask &= 0xFC; 218 mask |= nr; 219 } 220 if (mask != current_DOR) { 221 outb(mask,FD_DOR); 222 if ((mask ^ current_DOR) & 0xf0) 223 mon_timer[nr] = HZ/2; 224 else if (mon_timer[nr] < 2) 225 mon_timer[nr] = 2; 226 current_DOR = mask; 227 } 228 sti(); 229 return mon_timer[nr]; 230 } 231 232 void floppy_on(unsigned int nr) 233 { 234 cli(); 235 while (ticks_to_floppy_on(nr)) 236 sleep_on(nr+wait_motor); 237 sti(); 238 } 239 240 void floppy_off(unsigned int nr) 241 { 242 moff_timer[nr]=3*HZ; 243 } 244 245 void do_floppy_timer(void) 246 { 247 int i; 248 unsigned char mask = 0x10; 249 250 for (i=0 ; i<4 ; i++,mask <<= 1) { 251 if (!(mask & current_DOR)) 252 continue; 253 if (mon_timer[i]) { 254 if (!--mon_timer[i]) 255 wake_up(i+wait_motor); 256 } else if (!moff_timer[i]) { 257 current_DOR &= ~mask; 258 outb(current_DOR,FD_DOR); 259 } else 260 moff_timer[i]--; 261 } 262 } 263 264 #define TIME_REQUESTS 64 265 266 static struct timer_list { 267 long jiffies; 268 void (*fn)(); 269 struct timer_list * next; 270 } timer_list[TIME_REQUESTS], * next_timer = NULL; 271 272 void add_timer(long jiffies, void (*fn)(void)) 273 { 274 struct timer_list * p; 275 276 if (!fn) 277 return; 278 cli(); 279 if (jiffies <= 0) 280 (fn)(); 281 else { 282 for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++) 283 if (!p->fn) 284 break; 285 if (p >= timer_list + TIME_REQUESTS) 286 panic("No more time requests free"); 287 p->fn = fn; 288 p->jiffies = jiffies; 289 p->next = next_timer; 290 next_timer = p; 291 while (p->next && p->next->jiffies < p->jiffies) { 292 p->jiffies -= p->next->jiffies; 293 fn = p->fn; 294 p->fn = p->next->fn; 295 p->next->fn = fn; 296 jiffies = p->jiffies; 297 p->jiffies = p->next->jiffies; 298 p->next->jiffies = jiffies; 299 p = p->next; 300 } 301 } 302 sti(); 303 } 304 305 void do_timer(long cpl) 306 { 307 extern int beepcount; 308 extern void sysbeepstop(void); 309 310 if (beepcount) 311 if (!--beepcount) 312 sysbeepstop(); 313 314 if (cpl) 315 current->utime++; 316 else 317 current->stime++; 318 319 if (next_timer) { 320 next_timer->jiffies--; 321 while (next_timer && next_timer->jiffies <= 0) { 322 void (*fn)(void); 323 324 fn = next_timer->fn; 325 next_timer->fn = NULL; 326 next_timer = next_timer->next; 327 (fn)(); 328 } 329 } 330 if (current_DOR & 0xf0) 331 do_floppy_timer(); 332 if ((--current->counter)>0) return; 333 current->counter=0; 334 if (!cpl) return; 335 schedule(); 336 } 337 338 int sys_alarm(long seconds) 339 { 340 int old = current->alarm; 341 342 if (old) 343 old = (old - jiffies) / HZ; 344 current->alarm = (seconds>0)?(jiffies+HZ*seconds):0; 345 return (old); 346 } 347 348 int sys_getpid(void) 349 { 350 return current->pid; 351 } 352 353 int sys_getppid(void) 354 { 355 return current->father; 356 } 357 358 int sys_getuid(void) 359 { 360 return current->uid; 361 } 362 363 int sys_geteuid(void) 364 { 365 return current->euid; 366 } 367 368 int sys_getgid(void) 369 { 370 return current->gid; 371 } 372 373 int sys_getegid(void) 374 { 375 return current->egid; 376 } 377 378 int sys_nice(long increment) 379 { 380 if (current->priority-increment>0) 381 current->priority -= increment; 382 return 0; 383 } 384 385 void sched_init(void) 386 { 387 int i; 388 struct desc_struct * p; 389 390 if (sizeof(struct sigaction) != 16) 391 panic("Struct sigaction MUST be 16 bytes"); 392 set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss)); 393 set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt)); 394 p = gdt+2+FIRST_TSS_ENTRY; 395 for(i=1;i<NR_TASKS;i++) { 396 task[i] = NULL; 397 p->a=p->b=0; 398 p++; 399 p->a=p->b=0; 400 p++; 401 } 402 /* Clear NT, so that we won't have troubles with that later on */ 403 __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); 404 ltr(0); 405 lldt(0); 406 outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */ 407 outb_p(LATCH & 0xff , 0x40); /* LSB */ 408 outb(LATCH >> 8 , 0x40); /* MSB */ 409 set_intr_gate(0x20,&timer_interrupt); 410 outb(inb_p(0x21)&~0x01,0x21); 411 set_system_gate(0x80,&system_call); 412 } 413