लिनक्स/linux-0.01.tar/kernel/sched.c
< लिनक्स | linux-0.01.tar
/* * 'sched.c' is the main kernel file. It contains scheduling primitives * (sleep_on, wakeup, schedule etc) as well as a number of simple system * call functions (type getpid(), which just extracts a field from * current-task */ #include <linux/sched.h> #include <linux/kernel.h> #include <signal.h> #include <linux/sys.h> #include <asm/system.h> #include <asm/io.h> #include <asm/segment.h> #define LATCH (1193180/HZ) extern void mem_use(void); extern int timer_interrupt(void); extern int system_call(void); union task_union { struct task_struct task; char stack[PAGE_SIZE]; }; static union task_union init_task = {INIT_TASK,}; long volatile jiffies=0; long startup_time=0; struct task_struct *current = &(init_task.task), *last_task_used_math = NULL; struct task_struct * task[NR_TASKS] = {&(init_task.task), }; long user_stack [ PAGE_SIZE>>2 ] ; struct { long * a; short b; } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 }; /* * 'math_state_restore()' saves the current math information in the * old math state array, and gets the new ones from the current task */ void math_state_restore() { if (last_task_used_math) __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387)); if (current->used_math) __asm__("frstor %0"::"m" (current->tss.i387)); else { __asm__("fninit"::); current->used_math=1; } last_task_used_math=current; } /* * 'schedule()' is the scheduler function. This is GOOD CODE! There * probably won't be any reason to change this, as it should work well * in all circumstances (ie gives IO-bound processes good response etc). * The one thing you might take a look at is the signal-handler code here. * * NOTE!! Task 0 is the 'idle' task, which gets called when no other * tasks can run. It can not be killed, and it cannot sleep. The 'state' * information in task[0] is never used. */ void schedule(void) { int i,next,c; struct task_struct ** p; /* check alarm, wake up any interruptible tasks that have got a signal */ for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) if (*p) { if ((*p)->alarm && (*p)->alarm < jiffies) { (*p)->signal |= (1<<(SIGALRM-1)); (*p)->alarm = 0; } if ((*p)->signal && (*p)->state==TASK_INTERRUPTIBLE) (*p)->state=TASK_RUNNING; } /* this is the scheduler proper: */ while (1) { c = -1; next = 0; i = NR_TASKS; p = &task[NR_TASKS]; while (--i) { if (!*--p) continue; if ((*p)->state == TASK_RUNNING && (*p)->counter > c) c = (*p)->counter, next = i; } if (c) break; for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) if (*p) (*p)->counter = ((*p)->counter >> 1) + (*p)->priority; } switch_to(next); } int sys_pause(void) { current->state = TASK_INTERRUPTIBLE; schedule(); return 0; } void sleep_on(struct task_struct **p) { struct task_struct *tmp; if (!p) return; if (current == &(init_task.task)) panic("task[0] trying to sleep"); tmp = *p; *p = current; current->state = TASK_UNINTERRUPTIBLE; schedule(); if (tmp) tmp->state=0; } void interruptible_sleep_on(struct task_struct **p) { struct task_struct *tmp; if (!p) return; if (current == &(init_task.task)) panic("task[0] trying to sleep"); tmp=*p; *p=current; repeat: current->state = TASK_INTERRUPTIBLE; schedule(); if (*p && *p != current) { (**p).state=0; goto repeat; } *p=NULL; if (tmp) tmp->state=0; } void wake_up(struct task_struct **p) { if (p && *p) { (**p).state=0; *p=NULL; } } void do_timer(long cpl) { if (cpl) current->utime++; else current->stime++; if ((--current->counter)>0) return; current->counter=0; if (!cpl) return; schedule(); } int sys_alarm(long seconds) { current->alarm = (seconds>0)?(jiffies+HZ*seconds):0; return seconds; } int sys_getpid(void) { return current->pid; } int sys_getppid(void) { return current->father; } int sys_getuid(void) { return current->uid; } int sys_geteuid(void) { return current->euid; } int sys_getgid(void) { return current->gid; } int sys_getegid(void) { return current->egid; } int sys_nice(long increment) { if (current->priority-increment>0) current->priority -= increment; return 0; } int sys_signal(long signal,long addr,long restorer) { long i; switch (signal) { case SIGHUP: case SIGINT: case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGUSR1: case SIGSEGV: case SIGUSR2: case SIGPIPE: case SIGALRM: case SIGCHLD: i=(long) current->sig_fn[signal-1]; current->sig_fn[signal-1] = (fn_ptr) addr; current->sig_restorer = (fn_ptr) restorer; return i; default: return -1; } } void sched_init(void) { int i; struct desc_struct * p; set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss)); set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt)); p = gdt+2+FIRST_TSS_ENTRY; for(i=1;i<NR_TASKS;i++) { task[i] = NULL; p->a=p->b=0; p++; p->a=p->b=0; p++; } ltr(0); lldt(0); outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */ outb_p(LATCH & 0xff , 0x40); /* LSB */ outb(LATCH >> 8 , 0x40); /* MSB */ set_intr_gate(0x20,&timer_interrupt); outb(inb_p(0x21)&~0x01,0x21); set_system_gate(0x80,&system_call); }