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