diff --git a/miosix/kernel/kernel.cpp b/miosix/kernel/kernel.cpp index f637224775d82faf18cf4ed47e8dc09c374b040d..202b1de2c13ff8820587cdccf114ad3e2feaa500 100755 --- a/miosix/kernel/kernel.cpp +++ b/miosix/kernel/kernel.cpp @@ -272,7 +272,8 @@ void IRQaddToSleepingList(SleepData *x) while (it != sleepingList->end() && (*it)->wakeup_time < x->wakeup_time ) ++it; sleepingList->insert(it,x); } - //firstSleepItemTicks = tc->ns2tick(sleepingList->front()->wakeup_time); + //if (sleepingList->front()->wakeup_time < ContextSwitchTimer::instance().IRQgetCurrentTime()) + // ContextSwitchTimer::instance().IRQsetNextInterrupt(sleepingList->front()->wakeup_time); } /** @@ -281,7 +282,7 @@ void IRQaddToSleepingList(SleepData *x) * Also increases the system tick. * Takes care of clearing SLEEP_FLAG. * It is used by the kernel, and should not be used by end users. - * \return true if some thread was woken. + * \return true if some thread with higher priority of current thread is woken. */ bool IRQwakeThreads(long long currentTick) { @@ -298,14 +299,12 @@ bool IRQwakeThreads(long long currentTick) if((*it)->p == nullptr) ++it; //Only csRecord has p==nullptr else { (*it)->p->flags.IRQsetSleep(false); //Wake thread + if (const_cast<Thread*>(cur)->getPriority() < (*it)->p->getPriority()) + result = true; it = sleepingList->erase(it); - result = true; + } } -// if(sleepingList->empty()) -// firstSleepItemTicks = std::numeric_limits<long long>::max(); -// else -// firstSleepItemTicks = tc->ns2tick(sleepingList->front()->wakeup_time); return result; } @@ -394,8 +393,12 @@ void Thread::nanoSleepUntil(long long absoluteTime) d.wakeup_time = absoluteTime; IRQaddToSleepingList(&d);//Also sets SLEEP_FLAG } + // NOTE: There is no need to synchronize the timer (calling IRQsetNextInterrupt) + // with the list at this point. Because, Thread::yield will make a supervisor + // call and subsequently it will call the IRQfindNextThread. IRQfindNextThread + // keeps the timer synchronized with the sleeping list head and beginning of + // next burst time. (see ISR_yield() in portability.cpp Thread::yield(); - } void Thread::sleep(unsigned int ms) diff --git a/miosix/kernel/kernel.h b/miosix/kernel/kernel.h index d675a65084a0bb3ab17a1370dcddc0a86935bd0c..e2ae35d7ff1d9aa3f3a2eb3e0f067f4d71a5186b 100755 --- a/miosix/kernel/kernel.h +++ b/miosix/kernel/kernel.h @@ -1068,7 +1068,7 @@ public: */ bool operator() (Thread* a, Thread *b) { - return a->getPriority() < b->getPriority(); + return a->getPriority().mutexLessOp(b->getPriority()); } }; diff --git a/miosix/kernel/pthread_private.h b/miosix/kernel/pthread_private.h index 54c47156eb090230f1d396df94b43da947d00520..b05288c6e8bc10a52b7d2b1ef63c35306f639de3 100644 --- a/miosix/kernel/pthread_private.h +++ b/miosix/kernel/pthread_private.h @@ -172,7 +172,7 @@ static inline bool IRQdoMutexUnlock(pthread_mutex_t *mutex) mutex->first=mutex->first->next; #ifndef SCHED_TYPE_EDF - if(t->IRQgetPriority() >Thread::IRQgetCurrentThread()->IRQgetPriority()) + if(Thread::IRQgetCurrentThread()->IRQgetPriority() < t->IRQgetPriority()) return true; #endif //SCHED_TYPE_EDF return false; diff --git a/miosix/kernel/queue.h b/miosix/kernel/queue.h index 34dcf5fea76c649303183d03cf57555583b4dde0..eb8d78e40d20da07338cf653f5bab883f0af2676 100644 --- a/miosix/kernel/queue.h +++ b/miosix/kernel/queue.h @@ -277,8 +277,8 @@ bool Queue<T,len>::IRQget(T& elem) template <typename T, unsigned int len> bool Queue<T,len>::IRQget(T& elem, bool& hppw) { - if(waiting && (waiting->IRQgetPriority() > - Thread::IRQgetCurrentThread()->IRQgetPriority())) hppw=true; + if(waiting && (Thread::IRQgetCurrentThread()->IRQgetPriority()) < + waiting->IRQgetPriority()) hppw=true; IRQwakeWaitingThread(); if(isEmpty()) return false; numElem--; @@ -301,8 +301,8 @@ bool Queue<T,len>::IRQput(const T& elem) template <typename T, unsigned int len> bool Queue<T,len>::IRQput(const T& elem, bool& hppw) { - if(waiting && (waiting->IRQgetPriority() > - Thread::IRQgetCurrentThread()->IRQgetPriority())) hppw=true; + if(waiting && (Thread::IRQgetCurrentThread()->IRQgetPriority() < + waiting->IRQgetPriority())) hppw=true; IRQwakeWaitingThread(); if(isFull()) return false; numElem++; diff --git a/miosix/kernel/scheduler/control/control_scheduler.cpp b/miosix/kernel/scheduler/control/control_scheduler.cpp index 3c78b95570650f7b16ef15ecc7bdda5c8f5484a8..3de8f97b0a89b1fe52f24c6bda9d2d2e702dd41f 100644 --- a/miosix/kernel/scheduler/control/control_scheduler.cpp +++ b/miosix/kernel/scheduler/control/control_scheduler.cpp @@ -49,6 +49,7 @@ static ContextSwitchTimer& timer = ContextSwitchTimer::instance(); static long long burstStart = 0; static IntrusiveList<ThreadsListItem> activeThreads; static IntrusiveList<ThreadsListItem>::iterator curInRound = activeThreads.end(); +static long long nextPreemption = numeric_limits<long long>::max(); // // class ControlScheduler @@ -191,28 +192,30 @@ Thread *ControlScheduler::IRQgetIdleThread() return idle; } +long long ControlScheduler::IRQgetNextPreemption() +{ + return nextPreemption; +} + // Should be called when the current thread is the idle thread static inline void IRQsetNextPreemptionForIdle(){ if (sleepingList->empty()) - timer.IRQsetNextInterrupt(numeric_limits<long long>::max()); + nextPreemption = numeric_limits<long long>::max(); else - timer.IRQsetNextInterrupt(sleepingList->front()->wakeup_time); + nextPreemption = sleepingList->front()->wakeup_time; + timer.IRQsetNextInterrupt(nextPreemption); } // Should be called for threads other than idle thread static inline void IRQsetNextPreemption(long long burst){ long long firstWakeupInList; - long long nextPreemption; if (sleepingList->empty()) firstWakeupInList = numeric_limits<long long>::max(); else firstWakeupInList = sleepingList->front()->wakeup_time; burstStart = timer.IRQgetCurrentTime(); - nextPreemption = burstStart + burst; - if (firstWakeupInList < nextPreemption) - timer.IRQsetNextInterrupt(firstWakeupInList); - else - timer.IRQsetNextInterrupt(nextPreemption); + nextPreemption = min(firstWakeupInList,burstStart + burst); + timer.IRQsetNextInterrupt(nextPreemption); } unsigned int ControlScheduler::IRQfindNextThread() diff --git a/miosix/kernel/scheduler/control/control_scheduler.h b/miosix/kernel/scheduler/control/control_scheduler.h index 79221bd6339ba2c49379bac0c36d2bf78171aad0..08660520fe0b015c272a54b12a450230cb099a4e 100755 --- a/miosix/kernel/scheduler/control/control_scheduler.h +++ b/miosix/kernel/scheduler/control/control_scheduler.h @@ -146,6 +146,8 @@ public: * points to the currently running thread. */ static unsigned int IRQfindNextThread(); + + static long long IRQgetNextPreemption(); private: diff --git a/miosix/kernel/scheduler/control/control_scheduler_types.h b/miosix/kernel/scheduler/control/control_scheduler_types.h index c1cc128473c6275d46e8f271dffa7d9ea75dd7b5..f68608788dea07d990d108c963aed965c3337858 100755 --- a/miosix/kernel/scheduler/control/control_scheduler_types.h +++ b/miosix/kernel/scheduler/control/control_scheduler_types.h @@ -57,11 +57,11 @@ class Thread; //Forward declaration */ #define REALTIME_PRIORITY_NEXT_BURST 2 /** - * REALTIME_PRIORITY_NEXT_ROUND: The processor control is transfered to the thread - * in the next round and the thread is delayed until all remaining active threads - * are run. + * REALTIME_PRIORITY_END_OF_ROUND: The processor control is transfered to the + * thread in the end of the round and the thread is delayed until all remaining + * active threads are run. */ -#define REALTIME_PRIORITY_NEXT_ROUND 3 +#define REALTIME_PRIORITY_END_OF_ROUND 3 /** * This class models the concept of priority for the control based scheduler. @@ -79,7 +79,7 @@ public: * \param priority the desired priority value. */ ControlSchedulerPriority(short int priority): priority(priority), - realtime(REALTIME_PRIORITY_NEXT_ROUND) {} + realtime(REALTIME_PRIORITY_END_OF_ROUND) {} ControlSchedulerPriority(short int priority, short int realtime): priority(priority),realtime(realtime){} @@ -105,6 +105,18 @@ public: return this->priority>=0 && this->priority<PRIORITY_MAX && this->realtime >=1 && this->realtime<=3; } + + /** + * This function acts like a less-than operator but should be only used in + * synchronization module for priority inheritance. The concept of priority + * for preemption is not exactly the same for priority inheritance, hence, + * this operation is a branch out of preemption priority for inheritance + * purpose. + * @return + */ + inline bool mutexLessOp(ControlSchedulerPriority b){ + return false; + } private: short int priority;///< The priority value @@ -113,32 +125,21 @@ private: inline bool operator <(ControlSchedulerPriority a, ControlSchedulerPriority b) { - return a.getRealtime() < b.getRealtime(); + return b.getRealtime() == 1 && a.getRealtime() != 1; } -inline bool operator <=(ControlSchedulerPriority a, ControlSchedulerPriority b) -{ - return a.get() <= b.get(); -} - -inline bool operator >(ControlSchedulerPriority a, ControlSchedulerPriority b) -{ - return a.get() > b.get(); -} - -inline bool operator >=(ControlSchedulerPriority a, ControlSchedulerPriority b) -{ - return a.get() >= b.get(); +inline bool operator>(ControlSchedulerPriority a, ControlSchedulerPriority b){ + return a.getRealtime() == 1 && b.getRealtime() != 1; } inline bool operator ==(ControlSchedulerPriority a, ControlSchedulerPriority b) { - return a.get() == b.get(); + return a.getRealtime() == b.getRealtime(); } inline bool operator !=(ControlSchedulerPriority a, ControlSchedulerPriority b) { - return a.get() != b.get(); + return a.getRealtime() != b.getRealtime(); } struct ThreadsListItem : public IntrusiveListItem diff --git a/miosix/kernel/scheduler/priority/priority_scheduler.cpp b/miosix/kernel/scheduler/priority/priority_scheduler.cpp index f98dc6250b5ddefdd5c1fdb2084735ed315cbb43..1ecefc648349e0c73d98bff7efb363bae3bc227b 100644 --- a/miosix/kernel/scheduler/priority/priority_scheduler.cpp +++ b/miosix/kernel/scheduler/priority/priority_scheduler.cpp @@ -37,9 +37,12 @@ namespace miosix { //These are defined in kernel.cpp extern volatile Thread *cur; extern volatile int kernel_running; -static ContextSwitchTimer& timer = ContextSwitchTimer::instance(); extern IntrusiveList<SleepData> *sleepingList; +//Internal data +static ContextSwitchTimer& timer = ContextSwitchTimer::instance(); +static long long nextPeriodicPreemption = std::numeric_limits<long long>::max(); + // // class PriorityScheduler // @@ -200,16 +203,23 @@ void PriorityScheduler::IRQsetIdleThread(Thread *idleThread) idle=idleThread; } -static void setNextPreemption(bool curIsIdleThread){ +long long PriorityScheduler::IRQgetNextPreemption() +{ + return nextPeriodicPreemption; +} + +static void IRQsetNextPreemption(bool curIsIdleThread){ long long firstWakeupInList; if (sleepingList->empty()) firstWakeupInList = std::numeric_limits<long long>::max(); else firstWakeupInList = sleepingList->front()->wakeup_time; + if (curIsIdleThread){ timer.IRQsetNextInterrupt(firstWakeupInList); + nextPeriodicPreemption = std::numeric_limits<long long>::max(); }else{ - long long nextPeriodicPreemption = timer.IRQgetCurrentTime() + preemptionPeriodNs; + nextPeriodicPreemption = timer.IRQgetCurrentTime() + preemptionPeriodNs; if (firstWakeupInList < nextPeriodicPreemption ) timer.IRQsetNextInterrupt(firstWakeupInList); else @@ -246,7 +256,7 @@ unsigned int 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; - setNextPreemption(false); + IRQsetNextPreemption(false); return preemptionPeriodNs; } else temp=temp->schedData.next; if(temp==thread_list[i]->schedData.next) break; @@ -258,7 +268,7 @@ unsigned int PriorityScheduler::IRQfindNextThread() #ifdef WITH_PROCESSES MPUConfiguration::IRQdisable(); #endif //WITH_PROCESSES - setNextPreemption(true); + IRQsetNextPreemption(true); return preemptionPeriodNs; } diff --git a/miosix/kernel/scheduler/priority/priority_scheduler.h b/miosix/kernel/scheduler/priority/priority_scheduler.h index 24b2a3cfb49629fa74f82e89da6d72447140706b..e4fa55b736e3d4639e1812c6da457f02f05314af 100755 --- a/miosix/kernel/scheduler/priority/priority_scheduler.h +++ b/miosix/kernel/scheduler/priority/priority_scheduler.h @@ -139,6 +139,8 @@ public: * \return the burst time */ static unsigned int IRQfindNextThread(); + + static long long IRQgetNextPreemption(); private: diff --git a/miosix/kernel/scheduler/priority/priority_scheduler_types.h b/miosix/kernel/scheduler/priority/priority_scheduler_types.h index e58880c9b393ce242ba0f4a7be0eeaa033f6e932..51b40d163e3c11c30c1d5ed10e5db034067764d6 100644 --- a/miosix/kernel/scheduler/priority/priority_scheduler_types.h +++ b/miosix/kernel/scheduler/priority/priority_scheduler_types.h @@ -70,6 +70,18 @@ public: { return this->priority>=0 && this->priority<PRIORITY_MAX; } + + /** + * This function acts like a less-than operator but should be only used in + * synchronization module for priority inheritance. The concept of priority + * for preemption is not exactly the same for priority inheritance, hence, + * this operation is a branch out of preemption priority for inheritance + * purpose. + * @return + */ + inline bool mutexLessOp(PrioritySchedulerPriority b){ + return priority < b.priority; + } private: short int priority;///< The priority value @@ -80,21 +92,11 @@ inline bool operator <(PrioritySchedulerPriority a, PrioritySchedulerPriority b) return a.get() < b.get(); } -inline bool operator <=(PrioritySchedulerPriority a, PrioritySchedulerPriority b) -{ - return a.get() <= b.get(); -} - inline bool operator >(PrioritySchedulerPriority a, PrioritySchedulerPriority b) { return a.get() > b.get(); } -inline bool operator >=(PrioritySchedulerPriority a, PrioritySchedulerPriority b) -{ - return a.get() >= b.get(); -} - inline bool operator ==(PrioritySchedulerPriority a, PrioritySchedulerPriority b) { return a.get() == b.get(); diff --git a/miosix/kernel/scheduler/scheduler.h b/miosix/kernel/scheduler/scheduler.h index 047bc49fb0c2218c45ecf45731c3ad7499ae5e04..cb4043ed3457a68a48d4ae0391497b6173b2f1b8 100755 --- a/miosix/kernel/scheduler/scheduler.h +++ b/miosix/kernel/scheduler/scheduler.h @@ -169,7 +169,17 @@ public: { return T::IRQfindNextThread(); } - + + /** + * It returns the next preemption to be caused by the scheduler + * i.e. the beginning of the next burst. + * At the beginning, when no burst exists it returns + * numeric_limits<long long>::max(). + */ + static long long IRQgetNextPreemption() + { + return T::IRQgetNextPreemption(); + } }; #ifdef SCHED_TYPE_PRIORITY diff --git a/miosix/kernel/scheduler/timer_interrupt.h b/miosix/kernel/scheduler/timer_interrupt.h index 7de8fd6ff580cc782497dd5348dcd38b9ca03731..9615ca61b1c6e7755a96062f4456c0a7fa13a777 100644 --- a/miosix/kernel/scheduler/timer_interrupt.h +++ b/miosix/kernel/scheduler/timer_interrupt.h @@ -48,9 +48,12 @@ extern bool IRQwakeThreads(long long currentTick);///\internal Do not use outsid inline void IRQtimerInterrupt(long long currentTick) { miosix_private::IRQstackOverflowCheck(); - IRQwakeThreads(currentTick); + bool hptw = IRQwakeThreads(currentTick); + if (currentTick >= Scheduler::IRQgetNextPreemption() || hptw ){ + //End of the burst || a higher priority thread has woken up + Scheduler::IRQfindNextThread();//If the kernel is running, preempt + } - Scheduler::IRQfindNextThread();//If the kernel is running, preempt if(kernel_running!=0) tick_skew=true; #ifndef SCHED_TYPE_PRIORITY @@ -59,7 +62,7 @@ inline void IRQtimerInterrupt(long long currentTick) //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" + //#error "FIXME" #endif // miosix_private::IRQstackOverflowCheck(); diff --git a/miosix/kernel/sync.cpp b/miosix/kernel/sync.cpp index 733e7202a884ef4151db9501689f2b9182e8b1ce..9cb00348086cc5b8ae4dfefcb806dc363de011b1 100644 --- a/miosix/kernel/sync.cpp +++ b/miosix/kernel/sync.cpp @@ -81,7 +81,7 @@ void Mutex::PKlock(PauseKernelLock& dLock) //Handle priority inheritance if(p->mutexWaiting!=0) errorHandler(UNEXPECTED); p->mutexWaiting=this; - if(p->getPriority()>owner->getPriority()) + if (owner->getPriority().mutexLessOp(p->getPriority())) { Thread *walk=owner; for(;;) @@ -150,7 +150,7 @@ void Mutex::PKlockToDepth(PauseKernelLock& dLock, unsigned int depth) //Handle priority inheritance if(p->mutexWaiting!=0) errorHandler(UNEXPECTED); p->mutexWaiting=this; - if(p->getPriority()>owner->getPriority()) + if (owner->getPriority().mutexLessOp(p->getPriority())) { Thread *walk=owner; for(;;) @@ -250,7 +250,8 @@ bool Mutex::PKunlock(PauseKernelLock& dLock) while(walk!=0) { if(walk->waiting.empty()==false) - pr=max(pr,walk->waiting.front()->getPriority()); + if (pr.mutexLessOp(walk->waiting.front()->getPriority())) + pr = walk->waiting.front()->getPriority(); walk=walk->next; } if(pr!=owner->getPriority()) Scheduler::PKsetPriority(owner,pr); @@ -273,9 +274,9 @@ bool Mutex::PKunlock(PauseKernelLock& dLock) owner->mutexLocked=this; //Handle priority inheritance of new owner if(waiting.empty()==false && - waiting.front()->getPriority()>owner->getPriority()) + owner->getPriority().mutexLessOp(waiting.front()->getPriority())) Scheduler::PKsetPriority(owner,waiting.front()->getPriority()); - return owner->getPriority() > p->getPriority(); + return p->getPriority().mutexLessOp(owner->getPriority()); } else { owner=0; //No threads waiting std::vector<Thread *>().swap(waiting); //Save some RAM @@ -321,7 +322,8 @@ unsigned int Mutex::PKunlockAllDepthLevels(PauseKernelLock& dLock) while(walk!=0) { if(walk->waiting.empty()==false) - pr=max(pr,walk->waiting.front()->getPriority()); + if (pr.mutexLessOp(walk->waiting.front()->getPriority())) + pr = walk->waiting.front()->getPriority(); walk=walk->next; } if(pr!=owner->getPriority()) Scheduler::PKsetPriority(owner,pr); @@ -344,7 +346,7 @@ unsigned int Mutex::PKunlockAllDepthLevels(PauseKernelLock& dLock) owner->mutexLocked=this; //Handle priority inheritance of new owner if(waiting.empty()==false && - waiting.front()->getPriority()>owner->getPriority()) + owner->getPriority().mutexLessOp(waiting.front()->getPriority())) Scheduler::PKsetPriority(owner,waiting.front()->getPriority()); } else { owner=0; //No threads waiting @@ -430,8 +432,8 @@ void ConditionVariable::signal() //Wakeup first->p->flags.IRQsetCondWait(false); //Check for priority issues - if(first->p->IRQgetPriority() > - Thread::IRQgetCurrentThread()->IRQgetPriority()) hppw=true; + if(Thread::IRQgetCurrentThread()->IRQgetPriority() < + first->p->IRQgetPriority()) hppw=true; //Remove from list first=first->next; } @@ -452,8 +454,8 @@ void ConditionVariable::broadcast() //Wakeup first->p->flags.IRQsetCondWait(false); //Check for priority issues - if(first->p->IRQgetPriority() > - Thread::IRQgetCurrentThread()->IRQgetPriority()) hppw=true; + if(Thread::IRQgetCurrentThread()->IRQgetPriority() < + first->p->IRQgetPriority()) hppw=true; //Remove from list first=first->next; }