From e32fa7b409fc1cde1dbadb388cb31cec12450575 Mon Sep 17 00:00:00 2001
From: Terraneo Federico <fede.tft@hotmail.it>
Date: Mon, 27 Dec 2010 22:23:25 +0100
Subject: [PATCH] First working EDF implemetation, seems to meet deadlines
 without jitter

---
 Makefile                                      |  2 +-
 main.cpp                                      | 29 +++++++
 .../interfaces-impl/portability.cpp           | 32 +-------
 .../interfaces-impl/portability.cpp           | 32 +-------
 miosix/doc/textdoc/Changelog.txt              |  5 ++
 miosix/kernel/kernel.cpp                      | 15 +++-
 miosix/kernel/kernel.h                        |  2 +-
 miosix/kernel/scheduler/tick_interrupt.h      | 77 +++++++++++++++++++
 miosix/temp/loc_counter.sh                    |  4 +
 9 files changed, 136 insertions(+), 62 deletions(-)
 create mode 100644 miosix/kernel/scheduler/tick_interrupt.h
 create mode 100644 miosix/temp/loc_counter.sh

diff --git a/Makefile b/Makefile
index 0470d6c9..cbebdae8 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ SUBDIRS := miosix
 ## List here your source files (both .s, .c and .cpp)
 ##
 SRC :=                                  \
-testsuite.cpp
+main.cpp
 
 ##############################################################################
 ## You should not need to modify anything below                             ##
diff --git a/main.cpp b/main.cpp
index 785749c2..c12873ac 100644
--- a/main.cpp
+++ b/main.cpp
@@ -6,7 +6,36 @@
 using namespace std;
 using namespace miosix;
 
+typedef Gpio<GPIOF_BASE,6> led1;
+typedef Gpio<GPIOF_BASE,9> led2;
+
+void blinkThread(void *argv)
+{
+    const int period=static_cast<int>(TICK_FREQ*0.03);
+    long long tick=getTick();
+    for(;;)
+    {
+        if(led2::value()) led2::low(); else led2::high();
+        tick+=period;
+        Thread::setPriority(Priority(tick)); //Change deadline
+        Thread::sleepUntil(tick);
+    }
+}
+
 int main()
 {
     //iprintf("Hello world, write your application here\n");
+    led1::mode(Mode::OUTPUT);
+    led2::mode(Mode::OUTPUT);
+
+    Thread::create(blinkThread,STACK_MIN);
+    const int period=static_cast<int>(TICK_FREQ*0.05);
+    long long tick=getTick();
+    for(;;)
+    {
+        if(led1::value()) led1::low(); else led1::high();
+        tick+=period;
+        Thread::setPriority(Priority(tick)); //Change deadline
+        Thread::sleepUntil(tick);
+    }
 }
diff --git a/miosix/arch/arm7_lpc2000/lpc2138_miosix_board/interfaces-impl/portability.cpp b/miosix/arch/arm7_lpc2000/lpc2138_miosix_board/interfaces-impl/portability.cpp
index 5a3020e5..40abc8f7 100644
--- a/miosix/arch/arm7_lpc2000/lpc2138_miosix_board/interfaces-impl/portability.cpp
+++ b/miosix/arch/arm7_lpc2000/lpc2138_miosix_board/interfaces-impl/portability.cpp
@@ -32,6 +32,8 @@
 #include "kernel/error.h"
 #include "miosix.h"
 #include "portability_impl.h"
+#include "kernel/scheduler/scheduler.h"
+#include "kernel/scheduler/tick_interrupt.h"
 #include <algorithm>
 
 using namespace std;
@@ -39,19 +41,6 @@ using namespace std;
 //Used by the BSP. TODO: move this code into the "kernel thread"
 void tickHook();
 
-//These are defined in kernel.cpp
-namespace miosix {
-
-//Used by ISR_preempt
-extern unsigned char kernel_running;
-extern volatile bool tick_skew;
-extern volatile Thread *cur;
-
-//Used by ISR_preempt and ISR_yield
-extern bool IRQwakeThreads();
-
-}; //namespace miosix
-
 namespace miosix_private {
 
 /**
@@ -68,23 +57,8 @@ void ISR_preempt()
     VICVectAddr=0xff;//Restart VIC
     
     IRQstackOverflowCheck();
-    bool woken=miosix::IRQwakeThreads();//Increment tick and wake threads,if any
-    (void)woken; //Avoid unused variable warning.
+    miosix::IRQtickInterrupt();
 
-    #ifndef SCHED_TYPE_CONTROL_BASED
-    //With the control based scheduler preemption happens in the auxTimer
-    //routine since burst length is variable
-    miosix::Scheduler::IRQfindNextThread();//If the kernel is running, preempt
-    if(miosix::kernel_running!=0) miosix::tick_skew=true;//The kernel is not running
-    #else //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 && miosix::cur==miosix::ControlScheduler::IRQgetIdleThread())
-        miosix::Scheduler::IRQfindNextThread();
-    #endif //SCHED_TYPE_CONTROL_BASED
-    
     tickHook();
 }
 
diff --git a/miosix/arch/cortexM3_stm32/stm32f103ze_stm3210e-eval/interfaces-impl/portability.cpp b/miosix/arch/cortexM3_stm32/stm32f103ze_stm3210e-eval/interfaces-impl/portability.cpp
index 20171d06..62af7984 100644
--- a/miosix/arch/cortexM3_stm32/stm32f103ze_stm3210e-eval/interfaces-impl/portability.cpp
+++ b/miosix/arch/cortexM3_stm32/stm32f103ze_stm3210e-eval/interfaces-impl/portability.cpp
@@ -31,20 +31,9 @@
 #include "kernel/error.h"
 #include "interfaces/bsp.h"
 #include "kernel/scheduler/scheduler.h"
+#include "kernel/scheduler/tick_interrupt.h"
 #include <algorithm>
 
-//These are defined in kernel.cpp
-namespace miosix {
-
-//Used by ISR_preempt
-extern unsigned char kernel_running;
-extern volatile bool tick_skew;
-extern volatile Thread *cur;
-
-//Used by ISR_preempt and ISR_yield
-extern bool IRQwakeThreads();
-
-}; //namespace miosix
 
 /**
  * \internal
@@ -110,22 +99,7 @@ void ISR_preempt() __attribute__((noinline));
 void ISR_preempt()
 {
     IRQstackOverflowCheck();
-    bool woken=miosix::IRQwakeThreads();//Increment tick and wake threads,if any
-    (void)woken; //Avoid unused variable warning.
-
-    #ifndef SCHED_TYPE_CONTROL_BASED
-    //With the control based scheduler preemption happens in the auxTimer
-    //routine since burst length is variable
-    miosix::Scheduler::IRQfindNextThread();//If the kernel is running, preempt
-    if(miosix::kernel_running!=0) miosix::tick_skew=true;//The kernel is not running
-    #else //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 && miosix::cur==miosix::ControlScheduler::IRQgetIdleThread())
-        miosix::Scheduler::IRQfindNextThread();
-    #endif //SCHED_TYPE_CONTROL_BASED
+    miosix::IRQtickInterrupt();
 }
 
 /**
@@ -153,7 +127,7 @@ void ISR_auxTimer()
 {
     IRQstackOverflowCheck();
     miosix::Scheduler::IRQfindNextThread();//If the kernel is running, preempt
-    if(miosix::kernel_running!=0) miosix::tick_skew=true;//The kernel is not running
+    if(miosix::kernel_running!=0) miosix::tick_skew=true;
     TIM2->SR=0;
 }
 #endif //SCHED_TYPE_CONTROL_BASED
diff --git a/miosix/doc/textdoc/Changelog.txt b/miosix/doc/textdoc/Changelog.txt
index 0ecb9026..31bbfb5f 100644
--- a/miosix/doc/textdoc/Changelog.txt
+++ b/miosix/doc/textdoc/Changelog.txt
@@ -1,6 +1,11 @@
 Changelog for Miosix np embedded OS
 
 v1.56
+- Added preemption points in Thread::create(), Thread::setPriority() and
+  Thread::wakeup(), active if the EDF scheduler is selected.
+- Added file tick_interrupt.h with inline function IRQtickInterrupt() that
+  factorizes code for the tick interrupt that was repeated once per target
+  architecture.
 - Adapted EDF scheduler to use class Priority
 - Improved wakeup time in control based scheduler when waking from the idle
   thread.
diff --git a/miosix/kernel/kernel.cpp b/miosix/kernel/kernel.cpp
index ff89f20c..1023fa1a 100644
--- a/miosix/kernel/kernel.cpp
+++ b/miosix/kernel/kernel.cpp
@@ -337,6 +337,9 @@ Thread *Thread::create(void *(*startfunc)(void *), unsigned int stacksize,
         PauseKernelLock lock;
         Scheduler::PKaddThread(thread,priority);
     }
+    #ifdef SCHED_TYPE_EDF
+    if(isKernelRunning()) yield(); //The new thread might have a closer deadline
+    #endif //SCHED_TYPE_EDF
     return thread;
 }
 
@@ -459,6 +462,9 @@ void Thread::setPriority(Priority pr)
     //If old priority == desired priority, nothing to do.
     if(pr==current->getPriority()) return;
     Scheduler::PKsetPriority(current,pr);
+    #ifdef SCHED_TYPE_EDF
+    if(isKernelRunning()) yield(); //Another thread might have a closer deadline
+    #endif //SCHED_TYPE_EDF
 }
 
 void Thread::terminate()
@@ -483,8 +489,13 @@ void Thread::wait()
 void Thread::wakeup()
 {
     //pausing the kernel is not enough because of IRQwait and IRQwakeup
-    InterruptDisableLock lock;
-    this->flags.IRQsetWait(false);
+    {
+        InterruptDisableLock lock;
+        this->flags.IRQsetWait(false);
+    }
+    #ifdef SCHED_TYPE_EDF
+    if(isKernelRunning()) yield();//The other thread might have a closer deadline
+    #endif //SCHED_TYPE_EDF
 }
 
 void Thread::detach()
diff --git a/miosix/kernel/kernel.h b/miosix/kernel/kernel.h
index 944e6b29..25218952 100644
--- a/miosix/kernel/kernel.h
+++ b/miosix/kernel/kernel.h
@@ -421,7 +421,7 @@ public:
      *     {
      *         //Do work
      *         tick+=period;
-     *         Thread::sleepUntil(tick+period);
+     *         Thread::sleepUntil(tick);
      *     }
      * }
      * \endcode
diff --git a/miosix/kernel/scheduler/tick_interrupt.h b/miosix/kernel/scheduler/tick_interrupt.h
new file mode 100644
index 00000000..ab6b7600
--- /dev/null
+++ b/miosix/kernel/scheduler/tick_interrupt.h
@@ -0,0 +1,77 @@
+/***************************************************************************
+ *   Copyright (C) 2010 by Terraneo Federico                               *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   As a special exception, if other files instantiate templates or use   *
+ *   macros or inline functions from this file, or you compile this file   *
+ *   and link it with other works to produce a work based on this file,    *
+ *   this file does not by itself cause the resulting work to be covered   *
+ *   by the GNU General Public License. However the source code for this   *
+ *   file must still be made available in accordance with the GNU General  *
+ *   Public License. This exception does not invalidate any other reasons  *
+ *   why a work based on this file might be covered by the GNU General     *
+ *   Public License.                                                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, see <http://www.gnu.org/licenses/>   *
+ ***************************************************************************/
+
+#ifndef TICK_INTERRUPT_H
+#define	TICK_INTERRUPT_H
+
+#include "config/miosix_settings.h"
+#include "scheduler.h"
+
+namespace miosix {
+
+//These are a couple of global variables and a function that are part of the
+//internal implementation of the kernel and are defined in kernel.cpp
+//User code should not know about these nor try to use them.
+extern unsigned char 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
+
+inline void IRQtickInterrupt()
+{
+    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
+}
+
+}
+
+#endif //TICK_INTERRUPT_H
diff --git a/miosix/temp/loc_counter.sh b/miosix/temp/loc_counter.sh
new file mode 100644
index 00000000..0cb48615
--- /dev/null
+++ b/miosix/temp/loc_counter.sh
@@ -0,0 +1,4 @@
+#! /bin/bash
+
+# Count lines of code for Miosix
+find . | grep -E "\\.c|\\.cpp|\\.h" | xargs -d \\n cat | wc -l
-- 
GitLab