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