aboutsummaryrefslogtreecommitdiff
path: root/linux/kernel/sched.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/kernel/sched.c')
-rw-r--r--linux/kernel/sched.c254
1 files changed, 254 insertions, 0 deletions
diff --git a/linux/kernel/sched.c b/linux/kernel/sched.c
new file mode 100644
index 0000000..03399fa
--- /dev/null
+++ b/linux/kernel/sched.c
@@ -0,0 +1,254 @@
+/*
+ * '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);
+}