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 #include14 #include 15 #include 16 #include 17 #include 18 #include 19 #include 20 21 #include 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 >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 other101 * 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 kernel198 * proper. They are here because the floppy needs a timer, and this199 * 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 } else260 moff_timer[i]--;261 }262 }263 264 #define TIME_REQUESTS 64265 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 else317 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 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