root/kernel/sched.c

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

DEFINITIONS

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

   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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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\n\r",i,j);
  35 }
  36 
  37 void show_stat(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  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()
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 145 {
 146         current->state = TASK_INTERRUPTIBLE;
 147         schedule();
 148         return 0;
 149 }
 150 
 151 void sleep_on(struct task_struct **p)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 241 {
 242         moff_timer[nr]=3*HZ;
 243 }
 244 
 245 void do_floppy_timer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 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))
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 349 {
 350         return current->pid;
 351 }
 352 
 353 int sys_getppid(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 354 {
 355         return current->father;
 356 }
 357 
 358 int sys_getuid(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 359 {
 360         return current->uid;
 361 }
 362 
 363 int sys_geteuid(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 364 {
 365         return current->euid;
 366 }
 367 
 368 int sys_getgid(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 369 {
 370         return current->gid;
 371 }
 372 
 373 int sys_getegid(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 374 {
 375         return current->egid;
 376 }
 377 
 378 int sys_nice(long increment)
     /* [previous][next][first][last][top][bottom][index][help] */
 379 {
 380         if (current->priority-increment>0)
 381                 current->priority -= increment;
 382         return 0;
 383 }
 384 
 385 void sched_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

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