First steps to our own task switch
authorJens Krieg <jkrieg@mailbox.tu-berlin.de>
Wed, 22 May 2013 16:53:36 +0000 (18:53 +0200)
committerJens Krieg <jkrieg@mailbox.tu-berlin.de>
Wed, 22 May 2013 16:53:36 +0000 (18:53 +0200)
* task list still missing

arch/x86/kernel/process.c
kernel/sched.new/core.c
kernel/sched.new/sched.h

index 14ae100..197422d 100644 (file)
@@ -318,7 +318,7 @@ void cpu_idle(void)
         */
        boot_init_stack_canary();
        current_thread_info()->status |= TS_POLLING;
         */
        boot_init_stack_canary();
        current_thread_info()->status |= TS_POLLING;
-
+       printk("fertig k├Ânnen nach hause gehen!");
        while (1) {
                tick_nohz_idle_enter();
 
        while (1) {
                tick_nohz_idle_enter();
 
index 4d584fb..2563010 100644 (file)
@@ -9,10 +9,14 @@
  */
 
 #include <linux/init.h>
  */
 
 #include <linux/init.h>
+#include <asm/mmu_context.h>
 #include <linux/completion.h>
 #include <linux/kernel_stat.h>
 #include <linux/syscalls.h>
 #include <linux/completion.h>
 #include <linux/kernel_stat.h>
 #include <linux/syscalls.h>
+#include <linux/export.h>
+#include <linux/context_tracking.h>
 
 
+#include <asm/switch_to.h>
 #include <linux/cgroup.h>
 #include "sched.h"
 
 #include <linux/cgroup.h>
 #include "sched.h"
 
@@ -73,6 +77,17 @@ DEFINE_PER_CPU(struct kernel_stat, kstat);
 DEFINE_PER_CPU(struct kernel_cpustat, kernel_cpustat);
 
 
 DEFINE_PER_CPU(struct kernel_cpustat, kernel_cpustat);
 
 
+/*
+ * /kernel/sched/core.c:291
+ */
+__read_mostly int scheduler_running;
+
+/*
+ * kernel/sched/core.c:113
+ */
+DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
+
+
 
 
 
 
 
 
@@ -80,6 +95,132 @@ DEFINE_PER_CPU(struct kernel_cpustat, kernel_cpustat);
 // Functions
 //
 
 // Functions
 //
 
+/**
+ * kernel/sched/core.c:6872
+ * Initialize the scheduler
+ */
+void sched_init(void)
+{
+       int i;
+
+//     init_rt_bandwidth(&def_rt_bandwidth,
+//                     global_rt_period(), global_rt_runtime());
+
+       for_each_possible_cpu(i) {
+               struct rq *rq;
+
+               rq = cpu_rq(i);
+
+//             raw_spin_lock_init(&rq->lock);
+               rq->nr_running = 0;
+
+//             rq->calc_load_active = 0;
+//             rq->calc_load_update = jiffies + LOAD_FREQ;
+
+//             init_cfs_rq(&rq->cfs);
+//             init_rt_rq(&rq->rt, rq);
+
+//             rq->rt.rt_runtime = def_rt_bandwidth.rt_runtime;
+
+//             for (j = 0; j < CPU_LOAD_IDX_MAX; j++)
+//                     rq->cpu_load[j] = 0;
+
+//             rq->last_load_update_tick = jiffies;
+
+//             init_rq_hrtick(rq);
+//             atomic_set(&rq->nr_iowait, 0);
+       }
+
+//     set_load_weight(&init_task);
+
+       /*
+        * The boot idle thread does lazy MMU switching as well:
+        */
+//     atomic_inc(&init_mm.mm_count);
+//     enter_lazy_tlb(&init_mm, current);
+
+       /*
+        * Make us the idle thread. Technically, schedule() should not be
+        * called from this thread, however somewhere below it might be,
+        * but because we are the idle thread, we just pick up running again
+        * when this runqueue becomes "idle".
+        */
+       init_idle(current, smp_processor_id());
+
+//     calc_load_update = jiffies + LOAD_FREQ;
+
+       /*
+        * During early bootup we pretend to be a normal task:
+        */
+//     current->sched_class = &fair_sched_class;
+
+//     init_sched_fair_class();
+
+       scheduler_running = 1;
+}
+
+/**
+ * /kernel/sched/core.c:4674
+ * init_idle - set up an idle thread for a given CPU
+ * @idle: task in question
+ * @cpu: cpu the idle task belongs to
+ *
+ * NOTE: this function does not set the idle thread's NEED_RESCHED
+ * flag, to make booting more robust.
+ */
+void __cpuinit init_idle(struct task_struct *idle, int cpu)
+{
+       struct rq *rq = cpu_rq(cpu);
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&rq->lock, flags);
+
+       sched_fork(idle);
+       idle->state = TASK_RUNNING;
+       idle->se.exec_start = sched_clock();
+
+       rq->curr = rq->idle = idle;
+
+       raw_spin_unlock_irqrestore(&rq->lock, flags);
+
+       /* Set the preempt count _outside_ the spinlocks! */
+//     task_thread_info(idle)->preempt_count = 0;
+
+       /*
+        * The idle tasks have their own, simple scheduling class:
+        */
+//     idle->sched_class = &idle_sched_class;
+}
+
+/*
+ * kernel/sched/core.c:1622
+ * fork()/clone()-time setup:
+ */
+void sched_fork(struct task_struct *p)
+{
+       p->on_rq                        = 0;
+
+       p->se.on_rq                     = 0;
+       p->se.exec_start                = 0;
+       p->se.sum_exec_runtime          = 0;
+       p->se.prev_sum_exec_runtime     = 0;
+       p->se.nr_migrations             = 0;
+       p->se.vruntime                  = 0;
+       INIT_LIST_HEAD(&p->se.group_node);
+
+       /*
+        * We mark the process as running here. This guarantees that
+        * nobody will actually run it, and a signal or other external
+        * event cannot wake it up and insert it on the runqueue either.
+        */
+       p->state = TASK_RUNNING;
+
+       /*
+        * Make sure we do not leak PI boosting priority to the child.
+        */
+       p->prio = current->normal_prio;
+}
+
 /*
  * /kernel/sched/cputime.c:436
  * Account multiple ticks of idle time.
 /*
  * /kernel/sched/cputime.c:436
  * Account multiple ticks of idle time.
@@ -179,20 +320,6 @@ int idle_cpu(int cpu)
        return 0;
 }
 
        return 0;
 }
 
-/**
- * /kernel/sched/core.c:4674
- * init_idle - set up an idle thread for a given CPU
- * @idle: task in question
- * @cpu: cpu the idle task belongs to
- *
- * NOTE: this function does not set the idle thread's NEED_RESCHED
- * flag, to make booting more robust.
- */
-void __cpuinit init_idle(struct task_struct *idle, int cpu)
-{
-       return;
-}
-
 /*
  * /kernel/sched/core.c:4669
  * Sets sched_class of idle task, see struct sched_class idle_sched_class;
 /*
  * /kernel/sched/core.c:4669
  * Sets sched_class of idle task, see struct sched_class idle_sched_class;
@@ -273,15 +400,6 @@ void sched_clock_init(void)
        return;
 }
 
        return;
 }
 
-/*
- * kernel/sched/core.c:1622
- * fork()/clone()-time setup:
- */
-void sched_fork(struct task_struct *p)
-{
-       return;
-}
-
 /**
  * kernel/sched/core.c:4213
  * This functions stores the CPU affinity mask for the process or thread with the ID pid in the cpusetsize
 /**
  * kernel/sched/core.c:4213
  * This functions stores the CPU affinity mask for the process or thread with the ID pid in the cpusetsize
@@ -296,16 +414,6 @@ long sched_getaffinity(pid_t pid, struct cpumask *mask)
        return 0;
 }
 
        return 0;
 }
 
-/**
- * kernel/sched/core.c:6872
- * Initialize the scheduler
- */
-void sched_init(void)
-{
-       printk("sched init\n");
-       return;
-}
-
 /**
  * kernel/sched/core.c:6850
  */
 /**
  * kernel/sched/core.c:6850
  */
@@ -458,7 +566,10 @@ void update_cpu_load_nohz(void)
  */
 void wake_up_new_task(struct task_struct *tsk)
 {
  */
 void wake_up_new_task(struct task_struct *tsk)
 {
-       return;
+       struct rq *rq = cpu_rq(0);
+
+       //TODO: add new linked list to hold tasks
+       tsk->on_rq = 1;
 }
 
 /*
 }
 
 /*
@@ -466,7 +577,184 @@ void wake_up_new_task(struct task_struct *tsk)
  */
 int __sched _cond_resched(void)
 {
  */
 int __sched _cond_resched(void)
 {
-       return 0;
+       return 1;
+}
+
+/*
+ * kernel/sched/core.c:1931
+ * context_switch - switch to the new MM and the new
+ * thread's register state.
+ */
+static inline void
+context_switch(struct rq *rq, struct task_struct *prev,
+              struct task_struct *next)
+{
+       struct mm_struct *mm, *oldmm;
+
+//     prepare_task_switch(rq, prev, next);
+
+       mm = next->mm;
+       oldmm = prev->active_mm;
+       /*
+        * For paravirt, this is coupled with an exit in switch_to to
+        * combine the page table reload and the switch backend into
+        * one hypercall.
+        */
+//     arch_start_context_switch(prev);
+
+       if (!mm) {
+               next->active_mm = oldmm;
+               atomic_inc(&oldmm->mm_count);
+               enter_lazy_tlb(oldmm, next);
+       }
+       else
+               switch_mm(oldmm, mm, next);
+
+       if (!prev->mm) {
+               prev->active_mm = NULL;
+               rq->prev_mm = oldmm;
+       }
+       /*
+        * Since the runqueue lock will be released by the next
+        * task (which is an invalid locking op but in the case
+        * of the scheduler it's an obvious special-case), so we
+        * do an early lockdep release here:
+        */
+#ifndef __ARCH_WANT_UNLOCKED_CTXSW
+       spin_release(&rq->lock.dep_map, 1, _THIS_IP_);
+#endif
+
+       context_tracking_task_switch(prev, next);
+       /* Here we just switch the register state and the stack. */
+       switch_to(prev, next, prev);
+
+       barrier();
+       /*
+        * this_rq must be evaluated again because prev may have moved
+        * CPUs since it called schedule(), thus the 'rq' on its stack
+        * frame will be invalid.
+        */
+//     finish_task_switch(this_rq(), prev);
+       rq->prev_mm = NULL;
+}
+
+/*
+ * kernel/sched/core.c:2875
+ * __schedule() is the main scheduler function.
+ *
+ * The main means of driving the scheduler and thus entering this function are:
+ *
+ *   1. Explicit blocking: mutex, semaphore, waitqueue, etc.
+ *
+ *   2. TIF_NEED_RESCHED flag is checked on interrupt and userspace return
+ *      paths. For example, see arch/x86/entry_64.S.
+ *
+ *      To drive preemption between tasks, the scheduler sets the flag in timer
+ *      interrupt handler scheduler_tick().
+ *
+ *   3. Wakeups don't really cause entry into schedule(). They add a
+ *      task to the run-queue and that's it.
+ *
+ *      Now, if the new task added to the run-queue preempts the current
+ *      task, then the wakeup sets TIF_NEED_RESCHED and schedule() gets
+ *      called on the nearest possible occasion:
+ *
+ *       - If the kernel is preemptible (CONFIG_PREEMPT=y):
+ *
+ *         - in syscall or exception context, at the next outmost
+ *           preempt_enable(). (this might be as soon as the wake_up()'s
+ *           spin_unlock()!)
+ *
+ *         - in IRQ context, return from interrupt-handler to
+ *           preemptible context
+ *
+ *       - If the kernel is not preemptible (CONFIG_PREEMPT is not set)
+ *         then at the next:
+ *
+ *          - cond_resched() call
+ *          - explicit schedule() call
+ *          - return from syscall or exception to user-space
+ *          - return from interrupt-handler to user-space
+ */
+static void __sched __schedule(void)
+{
+       struct task_struct *prev, *next;
+       unsigned long *switch_count;
+       struct rq *rq;
+       int cpu;
+
+//need_resched:
+       preempt_disable();
+       cpu = smp_processor_id();
+       rq = cpu_rq(cpu);
+       rcu_note_context_switch(cpu);
+       prev = rq->curr;
+
+//     schedule_debug(prev);
+
+//     if (sched_feat(HRTICK))
+//             hrtick_clear(rq);
+
+//     raw_spin_lock_irq(&rq->lock);
+
+//     switch_count = &prev->nivcsw;
+//     if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
+//             if (unlikely(signal_pending_state(prev->state, prev))) {
+//                     prev->state = TASK_RUNNING;
+//             } else {
+//                     deactivate_task(rq, prev, DEQUEUE_SLEEP);
+//                     prev->on_rq = 0;
+//
+//                     /*
+//                      * If a worker went to sleep, notify and ask workqueue
+//                      * whether it wants to wake up a task to maintain
+//                      * concurrency.
+//                      */
+//                     if (prev->flags & PF_WQ_WORKER) {
+//                             struct task_struct *to_wakeup;
+//
+//                             to_wakeup = wq_worker_sleeping(prev, cpu);
+//                             if (to_wakeup)
+//                                     try_to_wake_up_local(to_wakeup);
+//                     }
+//             }
+//             switch_count = &prev->nvcsw;
+//     }
+//
+//     pre_schedule(rq, prev);
+//
+//     if (unlikely(!rq->nr_running))
+//             idle_balance(cpu, rq);
+
+//     put_prev_task(rq, prev);
+//     next = pick_next_task(rq);
+       next = (struct task_struct*)rq->curr->tasks.next;
+//     clear_tsk_need_resched(prev);
+       rq->skip_clock_update = 0;
+
+       if (likely(prev != next)) {
+               rq->nr_switches++;
+               rq->curr = next;
+//             ++*switch_count;
+
+               context_switch(rq, prev, next); /* unlocks the rq */
+               /*
+                * The context switch have flipped the stack from under us
+                * and restored the local variables which were saved when
+                * this task called schedule() in the past. prev == current
+                * is still correct, but it can be moved to another cpu/rq.
+                */
+               cpu = smp_processor_id();
+               rq = cpu_rq(cpu);
+       }
+       else
+               raw_spin_unlock_irq(&rq->lock);
+
+//     post_schedule(rq);
+
+       sched_preempt_enable_no_resched();
+//     if (need_resched())
+//             goto need_resched;
 }
 
 /*
 }
 
 /*
@@ -474,8 +762,9 @@ int __sched _cond_resched(void)
  */
 asmlinkage void __sched schedule(void)
 {
  */
 asmlinkage void __sched schedule(void)
 {
-       return;
+       __schedule();
 }
 }
+EXPORT_SYMBOL(schedule);
 
 /**
  * kernel/sched/core.c:3149
 
 /**
  * kernel/sched/core.c:3149
@@ -552,7 +841,9 @@ void complete(struct completion *x)
  */
 void __sched schedule_preempt_disabled(void)
 {
  */
 void __sched schedule_preempt_disabled(void)
 {
-       return;
+       sched_preempt_enable_no_resched();
+       schedule();
+       preempt_disable();
 }
 
 /*
 }
 
 /*
index 3cfe709..d683d38 100644 (file)
@@ -7,7 +7,47 @@ struct task_group {
 };
 
 struct rq {
 };
 
 struct rq {
-
+       /* runqueue lock: */
+       raw_spinlock_t lock;
+
+       /*
+        * nr_running and cpu_load should be in the same cacheline because
+        * remote CPUs use both these fields when doing load calculation.
+        */
+       unsigned int nr_running;
+       #define CPU_LOAD_IDX_MAX 5
+       unsigned long cpu_load[CPU_LOAD_IDX_MAX];
+       unsigned long last_load_update_tick;
+       int skip_clock_update;
+
+       /* capture load from *all* tasks on this cpu: */
+       struct load_weight load;
+       unsigned long nr_load_updates;
+       u64 nr_switches;
+
+       /*
+        * This is part of a global counter where only the total sum
+        * over all CPUs matters. A task can increase this counter on
+        * one CPU and if it got migrated afterwards it may decrease
+        * it on another CPU. Always updated under the runqueue lock:
+        */
+       unsigned long nr_uninterruptible;
+
+       struct task_struct *curr, *idle, *stop;
+       struct task_struct *next;
+       unsigned long next_balance;
+       struct mm_struct *prev_mm;
+
+       u64 clock;
+       u64 clock_task;
+
+       atomic_t nr_iowait;
+
+       /* calc_load related fields */
+       unsigned long calc_load_update;
+       long calc_load_active;
+
+       struct sched_avg avg;
 };
 
 DECLARE_PER_CPU(struct rq, runqueues);
 };
 
 DECLARE_PER_CPU(struct rq, runqueues);