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

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