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