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

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