|
|
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.2 root 32: #define _S(nr) (1<<((nr)-1))
33: #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
34:
1.1.1.10 root 35: static void show_task(int nr,struct task_struct * p)
1.1.1.2 root 36: {
1.1.1.3 root 37: int i,j = 4096-sizeof(struct task_struct);
38:
1.1.1.11! root 39: printk("%d: pid=%d, state=%d, father=%d, child=%d, ",(p == current)?-nr:nr,p->pid,
1.1.1.4 root 40: p->state, p->p_pptr->pid, p->p_cptr ? p->p_cptr->pid : -1);
1.1.1.3 root 41: i=0;
42: while (i<j && !((char *)(p+1))[i])
43: i++;
1.1.1.4 root 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");
1.1.1.2 root 52: }
53:
1.1.1.4 root 54: void show_state(void)
1.1.1.2 root 55: {
56: int i;
57:
1.1.1.4 root 58: printk("\rTask-info:\n\r");
1.1.1.7 root 59: for (i=0 ; i<NR_TASKS ; i++)
1.1.1.2 root 60: if (task[i])
61: show_task(i,task[i]);
62: }
63:
1.1 root 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:
1.1.1.9 root 76: static union task_union init_task = {INIT_TASK, };
1.1 root 77:
1.1.1.4 root 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:
1.1.1.2 root 86: struct task_struct *current = &(init_task.task);
87: struct task_struct *last_task_used_math = NULL;
1.1 root 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()
102: {
1.1.1.2 root 103: if (last_task_used_math == current)
104: return;
1.1.1.3 root 105: __asm__("fwait");
1.1.1.2 root 106: if (last_task_used_math) {
1.1 root 107: __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
1.1.1.2 root 108: }
1.1.1.3 root 109: last_task_used_math=current;
1.1.1.2 root 110: if (current->used_math) {
1.1 root 111: __asm__("frstor %0"::"m" (current->tss.i387));
1.1.1.2 root 112: } else {
1.1 root 113: __asm__("fninit"::);
114: current->used_math=1;
115: }
116: }
117:
118: /*
1.1.1.5 root 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.
1.1 root 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)
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:
1.1.1.8 root 134: need_resched = 0;
1.1 root 135: for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
136: if (*p) {
1.1.1.6 root 137: if ((*p)->timeout && (*p)->timeout < jiffies)
138: if ((*p)->state == TASK_INTERRUPTIBLE) {
139: (*p)->timeout = 0;
1.1.1.11! root 140: wake_one_task(*p);
1.1.1.6 root 141: }
1.1.1.5 root 142: if (((*p)->signal & ~(*p)->blocked) &&
1.1.1.11! root 143: (*p)->state==TASK_INTERRUPTIBLE)
! 144: wake_one_task(*p);
1.1 root 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)
170: {
1.1.1.5 root 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;
1.1 root 179: current->state = TASK_INTERRUPTIBLE;
180: schedule();
1.1.1.5 root 181: current->blocked = old_blocked;
182: return -EINTR;
1.1 root 183: }
184:
1.1.1.11! root 185: void wake_one_task(struct task_struct * p)
! 186: {
! 187: p->state = TASK_RUNNING;
! 188: if (p->counter > current->counter)
! 189: need_resched = 1;
! 190: }
! 191:
1.1.1.8 root 192: /*
193: * wake_up doesn't wake up stopped processes - they have to be awakened
194: * with signals or similar.
195: */
1.1.1.11! root 196: void wake_up(struct wait_queue **q)
1.1.1.6 root 197: {
1.1.1.11! root 198: struct wait_queue *tmp, *next;
! 199: struct task_struct * p;
! 200: unsigned long flags;
1.1.1.6 root 201:
1.1.1.11! root 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)
1.1.1.6 root 210: printk("wake_up: TASK_ZOMBIE\n");
1.1.1.11! root 211: else if (p->state != TASK_STOPPED) {
! 212: p->state = TASK_RUNNING;
! 213: if (p->counter > current->counter)
1.1.1.8 root 214: need_resched = 1;
215: }
1.1.1.6 root 216: }
1.1.1.11! root 217: tmp->next = NULL;
! 218: } while (next && next != *q);
! 219: __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
1.1.1.6 root 220: }
221:
1.1.1.11! root 222: static inline void __sleep_on(struct wait_queue **p, int state)
1.1 root 223: {
1.1.1.11! root 224: unsigned long flags;
1.1 root 225:
226: if (!p)
227: return;
1.1.1.6 root 228: if (current == task[0])
1.1 root 229: panic("task[0] trying to sleep");
1.1.1.11! root 230: if (current->wait.next)
! 231: printk("__sleep_on: wait->next exists\n");
! 232: __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
1.1.1.4 root 233: current->state = state;
1.1.1.11! root 234: add_wait_queue(p,¤t->wait);
1.1.1.5 root 235: sti();
1.1.1.6 root 236: schedule();
1.1.1.11! root 237: remove_wait_queue(p,¤t->wait);
1.1.1.5 root 238: __asm__("pushl %0 ; popfl"::"r" (flags));
1.1 root 239: }
240:
1.1.1.11! root 241: void interruptible_sleep_on(struct wait_queue **p)
1.1 root 242: {
1.1.1.4 root 243: __sleep_on(p,TASK_INTERRUPTIBLE);
244: }
1.1 root 245:
1.1.1.11! root 246: void sleep_on(struct wait_queue **p)
1.1.1.4 root 247: {
248: __sleep_on(p,TASK_UNINTERRUPTIBLE);
1.1 root 249: }
250:
1.1.1.2 root 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: */
1.1.1.11! root 256: static struct wait_queue * wait_motor[4] = {NULL,NULL,NULL,NULL};
1.1.1.2 root 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)
262: {
1.1.1.3 root 263: extern unsigned char selected;
264: unsigned char mask = 0x10 << nr;
1.1.1.2 root 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 */
1.1.1.3 root 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;
1.1.1.2 root 282: }
283: sti();
284: return mon_timer[nr];
285: }
286:
287: void floppy_off(unsigned int nr)
288: {
289: moff_timer[nr]=3*HZ;
290: }
291:
292: void do_floppy_timer(void)
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;
1.1.1.7 root 317: } timer_list[TIME_REQUESTS] = { { 0, NULL, NULL }, };
318:
319: static struct timer_list * next_timer = NULL;
1.1.1.2 root 320:
321: void add_timer(long jiffies, void (*fn)(void))
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:
1.1.1.8 root 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: };
1.1.1.9 root 365: unsigned long averunnable[3] = { 0, }; /* fixed point numbers */
1.1.1.8 root 366:
367: void update_avg(void)
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:
1.1.1.5 root 382: unsigned long timer_active = 0;
383: struct timer_struct timer_table[32];
384:
1.1.1.11! root 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)
1.1 root 392: {
1.1.1.5 root 393: unsigned long mask;
394: struct timer_struct *tp = timer_table+0;
1.1.1.9 root 395: struct task_struct ** task_p;
396: static int avg_cnt = 0;
1.1.1.4 root 397:
1.1.1.11! root 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;
1.1.1.5 root 416: }
1.1.1.9 root 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)) {
1.1.1.10 root 421: send_sig(SIGALRM,*task_p,1);
1.1.1.9 root 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;
1.1.1.10 root 428: send_sig(SIGPROF,current,1);
1.1.1.9 root 429: }
1.1.1.11! root 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();
1.1.1.9 root 440: }
1.1.1.2 root 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();
1.1 root 454: }
455:
456: int sys_alarm(long seconds)
457: {
1.1.1.9 root 458: extern int _setitimer(int, struct itimerval *, struct itimerval *);
459: struct itimerval new, old;
1.1.1.2 root 460:
1.1.1.9 root 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));
1.1 root 466: }
467:
468: int sys_getpid(void)
469: {
470: return current->pid;
471: }
472:
473: int sys_getppid(void)
474: {
1.1.1.4 root 475: return current->p_pptr->pid;
1.1 root 476: }
477:
478: int sys_getuid(void)
479: {
480: return current->uid;
481: }
482:
483: int sys_geteuid(void)
484: {
485: return current->euid;
486: }
487:
488: int sys_getgid(void)
489: {
490: return current->gid;
491: }
492:
493: int sys_getegid(void)
494: {
495: return current->egid;
496: }
497:
498: int sys_nice(long increment)
499: {
1.1.1.5 root 500: if (increment < 0 && !suser())
501: return -EPERM;
1.1.1.8 root 502: if (increment >= current->priority)
1.1.1.5 root 503: increment = current->priority-1;
504: current->priority -= increment;
1.1 root 505: return 0;
506: }
507:
508: void sched_init(void)
509: {
510: int i;
511: struct desc_struct * p;
512:
1.1.1.2 root 513: if (sizeof(struct sigaction) != 16)
514: panic("Struct sigaction MUST be 16 bytes");
1.1 root 515: set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));
516: set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
1.1.1.11! root 517: set_system_gate(0x80,&system_call);
1.1 root 518: p = gdt+2+FIRST_TSS_ENTRY;
1.1.1.5 root 519: for(i=1 ; i<NR_TASKS ; i++) {
1.1 root 520: task[i] = NULL;
521: p->a=p->b=0;
522: p++;
523: p->a=p->b=0;
524: p++;
525: }
1.1.1.3 root 526: /* Clear NT, so that we won't have troubles with that later on */
527: __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
1.1 root 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 */
1.1.1.11! root 533: request_irq(TIMER_IRQ,do_timer);
1.1 root 534: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.