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