From 799ea23a87e65f07f220f30e889157667ce9babb Mon Sep 17 00:00:00 2001
From: Terraneo Federico <fede.tft@miosix.org>
Date: Thu, 12 May 2016 18:32:25 +0200
Subject: [PATCH] Refactoring. TODO: check if it works (only compiled for now)

---
 .../common/interfaces-impl/portability.cpp    |  2 +-
 .../common/interfaces-impl/cstimer.cpp        | 40 +----------
 .../common/interfaces-impl/portability.cpp    |  4 +-
 miosix/interfaces/cstimer.h                   |  2 -
 miosix/kernel/kernel.cpp                      | 44 +++++++++++-
 miosix/kernel/kernel.h                        |  2 +-
 .../scheduler/priority/priority_scheduler.cpp |  9 ++-
 .../scheduler/priority/priority_scheduler.h   |  4 +-
 miosix/kernel/scheduler/scheduler.h           |  6 +-
 miosix/kernel/scheduler/timer_interrupt.h     | 69 +++++++++++--------
 10 files changed, 100 insertions(+), 82 deletions(-)

diff --git a/miosix/arch/cortexM3_efm32gg/common/interfaces-impl/portability.cpp b/miosix/arch/cortexM3_efm32gg/common/interfaces-impl/portability.cpp
index c5312beb..09f8d064 100644
--- a/miosix/arch/cortexM3_efm32gg/common/interfaces-impl/portability.cpp
+++ b/miosix/arch/cortexM3_efm32gg/common/interfaces-impl/portability.cpp
@@ -97,7 +97,7 @@ namespace miosix_private {
 void ISR_preempt() __attribute__((noinline));
 void ISR_preempt()
 {
-    miosix::IRQtimerInterrupt();
+    miosix::IRQtimerInterrupt(0 /*TODO dummy parameter */);
 }
 
 /**
diff --git a/miosix/arch/cortexM4_stm32f4/common/interfaces-impl/cstimer.cpp b/miosix/arch/cortexM4_stm32f4/common/interfaces-impl/cstimer.cpp
index 8bbbce9c..a62a0024 100644
--- a/miosix/arch/cortexM4_stm32f4/common/interfaces-impl/cstimer.cpp
+++ b/miosix/arch/cortexM4_stm32f4/common/interfaces-impl/cstimer.cpp
@@ -8,17 +8,11 @@
 
 using namespace miosix;
 
-namespace miosix {
-void IRQaddToSleepingList(SleepData *x);
-extern SleepData *sleeping_list;
-}
-
 //TODO: comment me
 static const uint32_t threshold = 0xffffffff/4*3;
 static long long ms32time = 0; //most significant 32 bits of counter
 static long long ms32chkp = 0; //most significant 32 bits of check point
 static bool lateIrq=false;
-static SleepData csRecord;
 
 static inline long long nextInterrupt()
 {
@@ -54,33 +48,8 @@ void __attribute__((used)) cstirqhnd()
         if(ms32time==ms32chkp || lateIrq)
         {
             lateIrq=false;
-            long long tick = IRQgetTick();
-            
-            //Add next context switch time to the sleeping list iff this is a
-            //context switch
             
-            if(tick >= csRecord.wakeup_time)
-            {
-                //Remove the cs item from the sleeping list manually
-                if(sleeping_list==&csRecord)
-                    sleeping_list=sleeping_list->next;
-                SleepData* slp = sleeping_list;
-                while(slp!=NULL)
-                {
-                    if(slp->next==&csRecord)
-                    {
-                        slp->next=slp->next->next;
-                        break;
-                    }
-                    slp = slp->next;
-                }
-                //Add next cs item to the list via IRQaddToSleepingList
-                //Note that the next timer interrupt is set by IRQaddToSleepingList
-                //according to the head of the list!
-                csRecord.wakeup_time += CST_QUANTUM;
-                IRQaddToSleepingList(&csRecord); //It would also set the next timer interrupt
-            }
-            IRQtimerInterrupt();
+            IRQtimerInterrupt(nextInterrupt());
         }
 
     }
@@ -166,13 +135,6 @@ ContextSwitchTimer::ContextSwitchTimer()
     TIM2->PSC = 0;
     TIM2->ARR = 0xFFFFFFFF;
     
-    // Other initializations
-    // Set the first checkpoint interrupt
-    csRecord.p = 0; //FIXME: remove these when removing direct sleeping_list access
-    csRecord.wakeup_time = CST_QUANTUM;
-    csRecord.next = sleeping_list;
-    sleeping_list = &csRecord;
-    // IRQaddToSleepingList(&csRecord); //Recursive Initialization error FIXME: why commented?
     // Enable TIM2 Counter
     ms32time = 0;
     TIM2->EGR = TIM_EGR_UG; //To enforce the timer to apply PSC (and other non-immediate settings)
diff --git a/miosix/arch/cortexM4_stm32f4/common/interfaces-impl/portability.cpp b/miosix/arch/cortexM4_stm32f4/common/interfaces-impl/portability.cpp
index 3fe65752..6f548766 100644
--- a/miosix/arch/cortexM4_stm32f4/common/interfaces-impl/portability.cpp
+++ b/miosix/arch/cortexM4_stm32f4/common/interfaces-impl/portability.cpp
@@ -106,7 +106,7 @@ namespace miosix_private {
 void ISR_preempt() __attribute__((noinline));
 void ISR_preempt()
 {
-    miosix::IRQtimerInterrupt();
+    miosix::IRQtimerInterrupt(0 /*TODO dummy parameter */);
 }
 #endif //USE_CSTIMER
 
@@ -312,8 +312,6 @@ void IRQportableStartKernel()
     SysTick->LOAD=SystemCoreClock/miosix::TICK_FREQ;
     SysTick->CTRL=SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk |
             SysTick_CTRL_CLKSOURCE_Msk;
-#else //USE ContextSwitchTimer class (TIM2)
-    miosix::ContextSwitchTimer::instance().IRQsetNextInterrupt(CST_QUANTUM);
 #endif
     #ifdef WITH_PROCESSES
     miosix::IRQenableMPUatBoot();
diff --git a/miosix/interfaces/cstimer.h b/miosix/interfaces/cstimer.h
index f1133782..6bb06eac 100644
--- a/miosix/interfaces/cstimer.h
+++ b/miosix/interfaces/cstimer.h
@@ -3,8 +3,6 @@
 
 namespace miosix {
 
-#define CST_QUANTUM 84000 ///FIXME: remove
-
 /**
  * This class is a low level interface to a hardware timer, that is used as
  * the basis for the Miosix timing infrastructure. In detail, it allows to
diff --git a/miosix/kernel/kernel.cpp b/miosix/kernel/kernel.cpp
index 924db01a..79e8c507 100644
--- a/miosix/kernel/kernel.cpp
+++ b/miosix/kernel/kernel.cpp
@@ -81,6 +81,13 @@ bool kernel_started=false;///<\internal becomes true after startKernel.
 /// calls to these functions.
 static unsigned char interruptDisableNesting=0;
 
+#ifdef USE_CSTIMER
+
+/// Used for context switches with the high resolution timer
+static SleepData csRecord;
+
+#endif //USE_CSTIMER
+
 #ifdef WITH_PROCESSES
 
 /// The proc field of the Thread class for kernel threads points to this object
@@ -200,9 +207,16 @@ void startKernel()
     // Make the C standard library use per-thread reeentrancy structure
     setCReentrancyCallback(Thread::getCReent);
     
-    // Now kernel is started
-
     // Dispatch the task to the architecture-specific function
+    #ifdef USE_CSTIMER
+    // Set the first checkpoint interrupt
+#define CST_QUANTUM 84000 //FIXME: find a way to propagate this here!!!
+    csRecord.p = 0;
+    csRecord.wakeup_time = CST_QUANTUM;
+    csRecord.next = sleeping_list;
+    sleeping_list = &csRecord;
+    miosix::ContextSwitchTimer::instance().IRQsetNextInterrupt(CST_QUANTUM);
+    #endif //USE_CSTIMER
     miosix_private::IRQportableStartKernel();
     kernel_started=true;
     miosix_private::IRQportableFinishKernelStartup();
@@ -279,10 +293,34 @@ void IRQaddToSleepingList(SleepData *x)
  * It is used by the kernel, and should not be used by end users.
  * \return true if some thread was woken.
  */
-bool IRQwakeThreads()
+bool IRQwakeThreads(long long currentTick, unsigned int burst)
 {
     #ifndef USE_CSTIMER
     tick++;//Increment tick
+    #else //USE_CSTIMER
+    //Add next context switch time to the sleeping list iff this is a
+    //context switch
+    if(currentTick >= csRecord.wakeup_time)
+    {
+        //Remove the cs item from the sleeping list manually
+        if(sleeping_list==&csRecord)
+            sleeping_list=sleeping_list->next;
+        SleepData* slp = sleeping_list;
+        while(slp!=NULL)
+        {
+            if(slp->next==&csRecord)
+            {
+                slp->next=slp->next->next;
+                break;
+            }
+            slp = slp->next;
+        }
+        //Add next cs item to the list via IRQaddToSleepingList
+        //Note that the next timer interrupt is set by IRQaddToSleepingList
+        //according to the head of the list!
+        csRecord.wakeup_time += burst;
+        IRQaddToSleepingList(&csRecord); //It would also set the next timer interrupt
+    }
     #endif //USE_CSTIMER
     bool result=false;
     for(;;)
diff --git a/miosix/kernel/kernel.h b/miosix/kernel/kernel.h
index a3dabf55..50c8d951 100644
--- a/miosix/kernel/kernel.h
+++ b/miosix/kernel/kernel.h
@@ -1010,7 +1010,7 @@ private:
     //Need access to status
     friend void IRQaddToSleepingList(SleepData *x);
     //Needs access to status
-    friend bool IRQwakeThreads();
+    friend bool IRQwakeThreads(long long currentTick, unsigned int burst);
     //Needs access to watermark, status, next
     friend void *idleThread(void *argv);
     //Needs to create the idle thread
diff --git a/miosix/kernel/scheduler/priority/priority_scheduler.cpp b/miosix/kernel/scheduler/priority/priority_scheduler.cpp
index 6f58904e..36453354 100644
--- a/miosix/kernel/scheduler/priority/priority_scheduler.cpp
+++ b/miosix/kernel/scheduler/priority/priority_scheduler.cpp
@@ -29,6 +29,8 @@
 #include "kernel/error.h"
 #include "kernel/process.h"
 
+static const unsigned int cstQuantum=84000; ///FIXME: remove
+
 #ifdef SCHED_TYPE_PRIORITY
 
 namespace miosix {
@@ -197,9 +199,9 @@ void PriorityScheduler::IRQsetIdleThread(Thread *idleThread)
     idle=idleThread;
 }
 
-void PriorityScheduler::IRQfindNextThread()
+unsigned int PriorityScheduler::IRQfindNextThread()
 {
-    if(kernel_running!=0) return;//If kernel is paused, do nothing
+    if(kernel_running!=0) return cstQuantum;//If kernel is paused, do nothing
     for(int i=PRIORITY_MAX-1;i>=0;i--)
     {
         if(thread_list[i]==NULL) continue;
@@ -226,7 +228,7 @@ void PriorityScheduler::IRQfindNextThread()
                 //Rotate to next thread so that next time the list is walked
                 //a different thread, if available, will be chosen first
                 thread_list[i]=temp;
-                return;
+                return cstQuantum;
             } else temp=temp->schedData.next;
             if(temp==thread_list[i]->schedData.next) break;
         }
@@ -237,6 +239,7 @@ void PriorityScheduler::IRQfindNextThread()
     #ifdef WITH_PROCESSES
     MPUConfiguration::IRQdisable();
     #endif //WITH_PROCESSES
+    return cstQuantum;
 }
 
 Thread *PriorityScheduler::thread_list[PRIORITY_MAX]={0};
diff --git a/miosix/kernel/scheduler/priority/priority_scheduler.h b/miosix/kernel/scheduler/priority/priority_scheduler.h
index 51004298..bc7d335f 100644
--- a/miosix/kernel/scheduler/priority/priority_scheduler.h
+++ b/miosix/kernel/scheduler/priority/priority_scheduler.h
@@ -136,8 +136,10 @@ public:
      * If the kernel is paused does nothing.
      * It's behaviour is to modify the global variable miosix::cur which always
      * points to the currently running thread.
+     * \return the burst or time quantum. That is, the time till the next
+     * preemption
      */
-    static void IRQfindNextThread();
+    static unsigned int IRQfindNextThread();
 
 private:
 
diff --git a/miosix/kernel/scheduler/scheduler.h b/miosix/kernel/scheduler/scheduler.h
index 08e1f162..566c98cc 100644
--- a/miosix/kernel/scheduler/scheduler.h
+++ b/miosix/kernel/scheduler/scheduler.h
@@ -163,10 +163,12 @@ public:
      * If the kernel is paused does nothing.
      * It's behaviour is to modify the global variable miosix::cur which always
      * points to the currently running thread.
+     * \return the burst or time quantum. That is, the time till the next
+     * preemption
      */
-    static void IRQfindNextThread()
+    static unsigned int IRQfindNextThread()
     {
-        T::IRQfindNextThread();
+        return T::IRQfindNextThread();
     }
 
 };
diff --git a/miosix/kernel/scheduler/timer_interrupt.h b/miosix/kernel/scheduler/timer_interrupt.h
index bd0d94ce..f7d05a74 100644
--- a/miosix/kernel/scheduler/timer_interrupt.h
+++ b/miosix/kernel/scheduler/timer_interrupt.h
@@ -40,38 +40,53 @@ namespace miosix {
 extern volatile int kernel_running;///\internal Do not use outside the kernel
 extern volatile bool tick_skew;///\internal Do not use outside the kernel
 extern volatile Thread *cur;///\internal Do not use outside the kernel
-extern bool IRQwakeThreads();///\internal Do not use outside the kernel
+extern bool IRQwakeThreads(long long currentTick, unsigned int burst);///\internal Do not use outside the kernel
 
-inline void IRQtimerInterrupt()
+inline void IRQtimerInterrupt(long long currentTick)
 {
     miosix_private::IRQstackOverflowCheck();
-    bool woken=IRQwakeThreads();//Increment tick and wake threads,if any
-    (void)woken; //Avoid unused variable warning.
-
-    #ifdef SCHED_TYPE_PRIORITY
-    //With the priority scheduler every tick causes a context switck
-    Scheduler::IRQfindNextThread();//If the kernel is running, preempt
+    
+    unsigned int burst=Scheduler::IRQfindNextThread();//If the kernel is running, preempt
     if(kernel_running!=0) tick_skew=true;
-    #elif defined(SCHED_TYPE_CONTROL_BASED)
-    //Normally, with the control based scheduler, preemptions do not happen
-    //here, but in the auxiliary timer interrupt to take into account variable
-    //bursts. But there is one exception: when a thread wakes up from sleep
-    //and the idle thread is running.
-    if(woken && cur==ControlScheduler::IRQgetIdleThread())
-    {
-        Scheduler::IRQfindNextThread();
-        if(kernel_running!=0) tick_skew=true;
-    }
-    #elif defined(SCHED_TYPE_EDF)
-    //With the EDF scheduler a preemption happens only if a thread with a closer
-    //deadline appears. So by deafult there is no need to call the scheduler;
-    //only if some threads were woken, they may have closer deadlines
-    if(woken)
-    {
-        Scheduler::IRQfindNextThread();
-        if(kernel_running!=0) tick_skew=true;
-    }
+    IRQwakeThreads(currentTick,burst);
+    
+    
+    #ifndef SCHED_TYPE_PRIORITY
+    //TODO: the old tick scheduler called this function periodically,
+    //so the EDF scheduler would have to be called only if a thread was woken.
+    //Now we can have no periodic preemption, and so if we are called (and EDF
+    //is selected), at least one thread has woken up, so there's no need for woken
+    //Modify the code below accordingly
+    #error "FIXME"
     #endif
+
+//    miosix_private::IRQstackOverflowCheck();
+//    bool woken=IRQwakeThreads();//Increment tick and wake threads,if any
+//    (void)woken; //Avoid unused variable warning.
+//    #ifdef SCHED_TYPE_PRIORITY
+//    //With the priority scheduler every tick causes a context switck
+//    Scheduler::IRQfindNextThread();//If the kernel is running, preempt
+//    if(kernel_running!=0) tick_skew=true;
+//    #elif defined(SCHED_TYPE_CONTROL_BASED)
+//    //Normally, with the control based scheduler, preemptions do not happen
+//    //here, but in the auxiliary timer interrupt to take into account variable
+//    //bursts. But there is one exception: when a thread wakes up from sleep
+//    //and the idle thread is running.
+//    if(woken && cur==ControlScheduler::IRQgetIdleThread())
+//    {
+//        Scheduler::IRQfindNextThread();
+//        if(kernel_running!=0) tick_skew=true;
+//    }
+//    #elif defined(SCHED_TYPE_EDF)
+//    //With the EDF scheduler a preemption happens only if a thread with a closer
+//    //deadline appears. So by deafult there is no need to call the scheduler;
+//    //only if some threads were woken, they may have closer deadlines
+//    if(woken)
+//    {
+//        Scheduler::IRQfindNextThread();
+//        if(kernel_running!=0) tick_skew=true;
+//    }
+//    #endif
 }
 
 }
-- 
GitLab