root/kernel/sched.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. show_task
  2. show_state
  3. math_state_restore
  4. schedule
  5. sys_pause
  6. wake_one_task
  7. wake_up
  8. __sleep_on
  9. interruptible_sleep_on
  10. sleep_on
  11. ticks_to_floppy_on
  12. floppy_off
  13. do_floppy_timer
  14. add_timer
  15. update_avg
  16. do_timer
  17. sys_alarm
  18. sys_getpid
  19. sys_getppid
  20. sys_getuid
  21. sys_geteuid
  22. sys_getgid
  23. sys_getegid
  24. sys_nice
  25. sched_init

   1 /*
   2  *  linux/kernel/sched.c
   3  *
   4  *  Copyright (C) 1991, 1992  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 
  14 #define TIMER_IRQ 0
  15 
  16 #include <linux/signal.h>
  17 #include <linux/sched.h>
  18 #include <linux/timer.h>
  19 #include <linux/kernel.h>
  20 #include <linux/sys.h>
  21 #include <linux/fdreg.h>
  22 #include <linux/errno.h>
  23 #include <linux/time.h>
  24 #include <linux/ptrace.h>
  25 
  26 #include <asm/system.h>
  27 #include <asm/io.h>
  28 #include <asm/segment.h>
  29 
  30 int need_resched = 0;
  31 
  32 #define _S(nr) (1<<((nr)-1))
  33 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
  34 
  35 static void show_task(int nr,struct task_struct * p)
     /* [previous][next][first][last][top][bottom][index][help] */
  36 {
  37         int i,j = 4096-sizeof(struct task_struct);
  38 
  39         printk("%d: pid=%d, state=%d, father=%d, child=%d, ",(p == current)?-nr:nr,p->pid,
  40                 p->state, p->p_pptr->pid, p->p_cptr ? p->p_cptr->pid : -1);
  41         i=0;
  42         while (i<j && !((char *)(p+1))[i])
  43                 i++;
  44         printk("%d/%d chars free in kstack\n\r",i,j);
  45         printk("   PC=%08X.", *(1019 + (unsigned long *) p));
  46         if (p->p_ysptr || p->p_osptr) 
  47                 printk("   Younger sib=%d, older sib=%d\n\r", 
  48                         p->p_ysptr ? p->p_ysptr->pid : -1,
  49                         p->p_osptr ? p->p_osptr->pid : -1);
  50         else
  51                 printk("\n\r");
  52 }
  53 
  54 void show_state(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {
  56         int i;
  57 
  58         printk("\rTask-info:\n\r");
  59         for (i=0 ; i<NR_TASKS ; i++)
  60                 if (task[i])
  61                         show_task(i,task[i]);
  62 }
  63 
  64 #define LATCH (1193180/HZ)
  65 
  66 extern void mem_use(void);
  67 
  68 extern int timer_interrupt(void);
  69 extern int system_call(void);
  70 
  71 union task_union {
  72         struct task_struct task;
  73         char stack[PAGE_SIZE];
  74 };
  75 
  76 static union task_union init_task = {INIT_TASK, };
  77 
  78 unsigned long volatile jiffies=0;
  79 unsigned long startup_time=0;
  80 int jiffies_offset = 0;         /* # clock ticks to add to get "true
  81                                    time".  Should always be less than
  82                                    1 second's worth.  For time fanatics
  83                                    who like to syncronize their machines
  84                                    to WWV :-) */
  85 
  86 struct task_struct *current = &(init_task.task);
  87 struct task_struct *last_task_used_math = NULL;
  88 
  89 struct task_struct * task[NR_TASKS] = {&(init_task.task), };
  90 
  91 long user_stack [ PAGE_SIZE>>2 ] ;
  92 
  93 struct {
  94         long * a;
  95         short b;
  96         } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 };
  97 /*
  98  *  'math_state_restore()' saves the current math information in the
  99  * old math state array, and gets the new ones from the current task
 100  */
 101 void math_state_restore()
     /* [previous][next][first][last][top][bottom][index][help] */
 102 {
 103         if (last_task_used_math == current)
 104                 return;
 105         __asm__("fwait");
 106         if (last_task_used_math) {
 107                 __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
 108         }
 109         last_task_used_math=current;
 110         if (current->used_math) {
 111                 __asm__("frstor %0"::"m" (current->tss.i387));
 112         } else {
 113                 __asm__("fninit"::);
 114                 current->used_math=1;
 115         }
 116 }
 117 
 118 /*
 119  *  'schedule()' is the scheduler function. It's a very simple and nice
 120  * scheduler: it's not perfect, but certainly works for most things.
 121  * The one thing you might take a look at is the signal-handler code here.
 122  *
 123  *   NOTE!!  Task 0 is the 'idle' task, which gets called when no other
 124  * tasks can run. It can not be killed, and it cannot sleep. The 'state'
 125  * information in task[0] is never used.
 126  */
 127 void schedule(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 128 {
 129         int i,next,c;
 130         struct task_struct ** p;
 131 
 132 /* check alarm, wake up any interruptible tasks that have got a signal */
 133 
 134         need_resched = 0;
 135         for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
 136                 if (*p) {
 137                         if ((*p)->timeout && (*p)->timeout < jiffies)
 138                                 if ((*p)->state == TASK_INTERRUPTIBLE) {
 139                                         (*p)->timeout = 0;
 140                                         wake_one_task(*p);
 141                                 }
 142                         if (((*p)->signal & ~(*p)->blocked) &&
 143                             (*p)->state==TASK_INTERRUPTIBLE)
 144                                 wake_one_task(*p);
 145                 }
 146 
 147 /* this is the scheduler proper: */
 148 
 149         while (1) {
 150                 c = -1;
 151                 next = 0;
 152                 i = NR_TASKS;
 153                 p = &task[NR_TASKS];
 154                 while (--i) {
 155                         if (!*--p)
 156                                 continue;
 157                         if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
 158                                 c = (*p)->counter, next = i;
 159                 }
 160                 if (c) break;
 161                 for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
 162                         if (*p)
 163                                 (*p)->counter = ((*p)->counter >> 1) +
 164                                                 (*p)->priority;
 165         }
 166         switch_to(next);
 167 }
 168 
 169 int sys_pause(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 170 {
 171         unsigned long old_blocked;
 172         unsigned long mask;
 173         struct sigaction * sa = current->sigaction;
 174 
 175         old_blocked = current->blocked;
 176         for (mask=1 ; mask ; sa++,mask += mask)
 177                 if (sa->sa_handler == SIG_IGN)
 178                         current->blocked |= mask;
 179         current->state = TASK_INTERRUPTIBLE;
 180         schedule();
 181         current->blocked = old_blocked;
 182         return -EINTR;
 183 }
 184 
 185 void wake_one_task(struct task_struct * p)
     /* [previous][next][first][last][top][bottom][index][help] */
 186 {
 187         p->state = TASK_RUNNING;
 188         if (p->counter > current->counter)
 189                 need_resched = 1;
 190 }
 191 
 192 /*
 193  * wake_up doesn't wake up stopped processes - they have to be awakened
 194  * with signals or similar.
 195  */
 196 void wake_up(struct wait_queue **q)
     /* [previous][next][first][last][top][bottom][index][help] */
 197 {
 198         struct wait_queue *tmp, *next;
 199         struct task_struct * p;
 200         unsigned long flags;
 201 
 202         if (!q || !(next = *q))
 203                 return;
 204         __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
 205         do {
 206                 tmp = next;
 207                 next = tmp->next;
 208                 if (p = tmp->task) {
 209                         if (p->state == TASK_ZOMBIE)
 210                                 printk("wake_up: TASK_ZOMBIE\n");
 211                         else if (p->state != TASK_STOPPED) {
 212                                 p->state = TASK_RUNNING;
 213                                 if (p->counter > current->counter)
 214                                         need_resched = 1;
 215                         }
 216                 }
 217                 tmp->next = NULL;
 218         } while (next && next != *q);
 219         __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
 220 }
 221 
 222 static inline void __sleep_on(struct wait_queue **p, int state)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224         unsigned long flags;
 225 
 226         if (!p)
 227                 return;
 228         if (current == task[0])
 229                 panic("task[0] trying to sleep");
 230         if (current->wait.next)
 231                 printk("__sleep_on: wait->next exists\n");
 232         __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
 233         current->state = state;
 234         add_wait_queue(p,&current->wait);
 235         sti();
 236         schedule();
 237         remove_wait_queue(p,&current->wait);
 238         __asm__("pushl %0 ; popfl"::"r" (flags));
 239 }
 240 
 241 void interruptible_sleep_on(struct wait_queue **p)
     /* [previous][next][first][last][top][bottom][index][help] */
 242 {
 243         __sleep_on(p,TASK_INTERRUPTIBLE);
 244 }
 245 
 246 void sleep_on(struct wait_queue **p)
     /* [previous][next][first][last][top][bottom][index][help] */
 247 {
 248         __sleep_on(p,TASK_UNINTERRUPTIBLE);
 249 }
 250 
 251 /*
 252  * OK, here are some floppy things that shouldn't be in the kernel
 253  * proper. They are here because the floppy needs a timer, and this
 254  * was the easiest way of doing it.
 255  */
 256 static struct wait_queue * wait_motor[4] = {NULL,NULL,NULL,NULL};
 257 static int  mon_timer[4]={0,0,0,0};
 258 static int moff_timer[4]={0,0,0,0};
 259 unsigned char current_DOR = 0x0C;
 260 
 261 int ticks_to_floppy_on(unsigned int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 262 {
 263         extern unsigned char selected;
 264         unsigned char mask = 0x10 << nr;
 265 
 266         if (nr>3)
 267                 panic("floppy_on: nr>3");
 268         moff_timer[nr]=10000;           /* 100 s = very big :-) */
 269         cli();                          /* use floppy_off to turn it off */
 270         mask |= current_DOR;
 271         if (!selected) {
 272                 mask &= 0xFC;
 273                 mask |= nr;
 274         }
 275         if (mask != current_DOR) {
 276                 outb(mask,FD_DOR);
 277                 if ((mask ^ current_DOR) & 0xf0)
 278                         mon_timer[nr] = HZ/2;
 279                 else if (mon_timer[nr] < 2)
 280                         mon_timer[nr] = 2;
 281                 current_DOR = mask;
 282         }
 283         sti();
 284         return mon_timer[nr];
 285 }
 286 
 287 void floppy_off(unsigned int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 288 {
 289         moff_timer[nr]=3*HZ;
 290 }
 291 
 292 void do_floppy_timer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 293 {
 294         int i;
 295         unsigned char mask = 0x10;
 296 
 297         for (i=0 ; i<4 ; i++,mask <<= 1) {
 298                 if (!(mask & current_DOR))
 299                         continue;
 300                 if (mon_timer[i]) {
 301                         if (!--mon_timer[i])
 302                                 wake_up(i+wait_motor);
 303                 } else if (!moff_timer[i]) {
 304                         current_DOR &= ~mask;
 305                         outb(current_DOR,FD_DOR);
 306                 } else
 307                         moff_timer[i]--;
 308         }
 309 }
 310 
 311 #define TIME_REQUESTS 64
 312 
 313 static struct timer_list {
 314         long jiffies;
 315         void (*fn)();
 316         struct timer_list * next;
 317 } timer_list[TIME_REQUESTS] = { { 0, NULL, NULL }, };
 318 
 319 static struct timer_list * next_timer = NULL;
 320 
 321 void add_timer(long jiffies, void (*fn)(void))
     /* [previous][next][first][last][top][bottom][index][help] */
 322 {
 323         struct timer_list * p;
 324 
 325         if (!fn)
 326                 return;
 327         cli();
 328         if (jiffies <= 0)
 329                 (fn)();
 330         else {
 331                 for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++)
 332                         if (!p->fn)
 333                                 break;
 334                 if (p >= timer_list + TIME_REQUESTS)
 335                         panic("No more time requests free");
 336                 p->fn = fn;
 337                 p->jiffies = jiffies;
 338                 p->next = next_timer;
 339                 next_timer = p;
 340                 while (p->next && p->next->jiffies < p->jiffies) {
 341                         p->jiffies -= p->next->jiffies;
 342                         fn = p->fn;
 343                         p->fn = p->next->fn;
 344                         p->next->fn = fn;
 345                         jiffies = p->jiffies;
 346                         p->jiffies = p->next->jiffies;
 347                         p->next->jiffies = jiffies;
 348                         p = p->next;
 349                 }
 350         }
 351         sti();
 352 }
 353 
 354 #define FSHIFT  11
 355 #define FSCALE  (1<<FSHIFT)
 356 /*
 357  * Constants for averages over 1, 5, and 15 minutes
 358  * when sampling at 5 second intervals.
 359  */
 360 static unsigned long cexp[3] = {
 361         1884,   /* 0.9200444146293232 * FSCALE,  exp(-1/12) */
 362         2014,   /* 0.9834714538216174 * FSCALE,  exp(-1/60) */
 363         2037,   /* 0.9944598480048967 * FSCALE,  exp(-1/180) */
 364 };
 365 unsigned long averunnable[3] = { 0, };  /* fixed point numbers */
 366 
 367 void update_avg(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 368 {
 369         int i, n=0;
 370         struct task_struct **p;
 371 
 372         for(p = &LAST_TASK; p > &FIRST_TASK; --p)
 373                 if (*p && ((*p)->state == TASK_RUNNING || 
 374                            (*p)->state == TASK_UNINTERRUPTIBLE))
 375                         ++n;
 376         
 377         for (i = 0; i < 3; ++i)
 378                 averunnable[i] = (cexp[i] * averunnable[i] +
 379                         n * FSCALE * (FSCALE - cexp[i])) >> FSHIFT;
 380 }
 381 
 382 unsigned long timer_active = 0;
 383 struct timer_struct timer_table[32];
 384 
 385 /*
 386  * The int argument is really a (struct pt_regs *), in case the
 387  * interrupt wants to know from where it was called. The timer
 388  * irq uses this to decide if it should update the user or system
 389  * times.
 390  */
 391 static void do_timer(int regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 392 {
 393         unsigned long mask;
 394         struct timer_struct *tp = timer_table+0;
 395         struct task_struct ** task_p;
 396         static int avg_cnt = 0;
 397 
 398         jiffies++;
 399         if (3 & ((struct pt_regs *) regs)->cs)
 400                 current->utime++;
 401         else {
 402                 current->stime++;
 403                 /* Update ITIMER_VIRT for current task if not in a system call */
 404                 if (current->it_virt_value && !(--current->it_virt_value)) {
 405                         current->it_virt_value = current->it_virt_incr;
 406                         send_sig(SIGVTALRM,current,1);
 407                 }
 408         }
 409         if (--avg_cnt < 0) {
 410                 avg_cnt = 500;
 411                 update_avg();
 412         }
 413         if ((--current->counter)<=0) {
 414                 current->counter=0;
 415                 need_resched = 1;
 416         }
 417         /* Update ITIMER_REAL for every task */
 418         for (task_p = &LAST_TASK; task_p >= &FIRST_TASK; task_p--)
 419                 if (*task_p && (*task_p)->it_real_value
 420                         && !(--(*task_p)->it_real_value)) {
 421                         send_sig(SIGALRM,*task_p,1);
 422                         (*task_p)->it_real_value = (*task_p)->it_real_incr;
 423                         need_resched = 1;
 424                 }
 425         /* Update ITIMER_PROF for the current task */
 426         if (current->it_prof_value && !(--current->it_prof_value)) {
 427                 current->it_prof_value = current->it_prof_incr;
 428                 send_sig(SIGPROF,current,1);
 429         }
 430         for (mask = 1 ; mask ; tp++,mask += mask) {
 431                 if (mask > timer_active)
 432                         break;
 433                 if (!(mask & timer_active))
 434                         continue;
 435                 if (tp->expires > jiffies)
 436                         continue;
 437                 timer_active &= ~mask;
 438                 tp->fn();
 439                 sti();
 440         }
 441         if (next_timer) {
 442                 next_timer->jiffies--;
 443                 while (next_timer && next_timer->jiffies <= 0) {
 444                         void (*fn)(void);
 445                         
 446                         fn = next_timer->fn;
 447                         next_timer->fn = NULL;
 448                         next_timer = next_timer->next;
 449                         (fn)();
 450                 }
 451         }
 452         if (current_DOR & 0xf0)
 453                 do_floppy_timer();
 454 }
 455 
 456 int sys_alarm(long seconds)
     /* [previous][next][first][last][top][bottom][index][help] */
 457 {
 458         extern int _setitimer(int, struct itimerval *, struct itimerval *);
 459         struct itimerval new, old;
 460 
 461         new.it_interval.tv_sec = new.it_interval.tv_usec = 0;
 462         new.it_value.tv_sec = seconds;
 463         new.it_value.tv_usec = 0;
 464         _setitimer(ITIMER_REAL, &new, &old);
 465         return(old.it_value.tv_sec + (old.it_value.tv_usec / 1000000));
 466 }
 467 
 468 int sys_getpid(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 469 {
 470         return current->pid;
 471 }
 472 
 473 int sys_getppid(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 474 {
 475         return current->p_pptr->pid;
 476 }
 477 
 478 int sys_getuid(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 479 {
 480         return current->uid;
 481 }
 482 
 483 int sys_geteuid(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 484 {
 485         return current->euid;
 486 }
 487 
 488 int sys_getgid(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 489 {
 490         return current->gid;
 491 }
 492 
 493 int sys_getegid(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 494 {
 495         return current->egid;
 496 }
 497 
 498 int sys_nice(long increment)
     /* [previous][next][first][last][top][bottom][index][help] */
 499 {
 500         if (increment < 0 && !suser())
 501                 return -EPERM;
 502         if (increment >= current->priority)
 503                 increment = current->priority-1;
 504         current->priority -= increment;
 505         return 0;
 506 }
 507 
 508 void sched_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 509 {
 510         int i;
 511         struct desc_struct * p;
 512 
 513         if (sizeof(struct sigaction) != 16)
 514                 panic("Struct sigaction MUST be 16 bytes");
 515         set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));
 516         set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
 517         set_system_gate(0x80,&system_call);
 518         p = gdt+2+FIRST_TSS_ENTRY;
 519         for(i=1 ; i<NR_TASKS ; i++) {
 520                 task[i] = NULL;
 521                 p->a=p->b=0;
 522                 p++;
 523                 p->a=p->b=0;
 524                 p++;
 525         }
 526 /* Clear NT, so that we won't have troubles with that later on */
 527         __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
 528         ltr(0);
 529         lldt(0);
 530         outb_p(0x36,0x43);              /* binary, mode 3, LSB/MSB, ch 0 */
 531         outb_p(LATCH & 0xff , 0x40);    /* LSB */
 532         outb(LATCH >> 8 , 0x40);        /* MSB */
 533         request_irq(TIMER_IRQ,do_timer);
 534 }

/* [previous][next][first][last][top][bottom][index][help] */