From 4b69d7ea03c8f171e6819a793217b02650d37997 Mon Sep 17 00:00:00 2001 From: Terraneo Federico <fede.tft@miosix.org> Date: Sun, 26 Mar 2023 14:35:15 +0200 Subject: [PATCH] Implement timedWait also in class ConditonVariable --- miosix/kernel/kernel.h | 20 ++-- miosix/kernel/pthread.cpp | 79 +++++++++------- miosix/kernel/pthread_private.h | 14 +-- miosix/kernel/sync.cpp | 163 ++++++++++++++++++-------------- miosix/kernel/sync.h | 90 +++++++++++++----- 5 files changed, 216 insertions(+), 150 deletions(-) diff --git a/miosix/kernel/kernel.h b/miosix/kernel/kernel.h index c7eb36af..7c8c054f 100755 --- a/miosix/kernel/kernel.h +++ b/miosix/kernel/kernel.h @@ -1039,18 +1039,18 @@ private: //friend functions //Need access to status - friend void IRQaddToSleepingList(SleepData *x); + friend void IRQaddToSleepingList(SleepData *); //Need access to status - friend void IRQremoveFromSleepingList(SleepData *x); + friend void IRQremoveFromSleepingList(SleepData *); //Needs access to status - friend bool IRQwakeThreads(long long currentTick); + friend bool IRQwakeThreads(long long); //Needs access to watermark, status, next - friend void *idleThread(void *argv); + friend void *idleThread(void *); //Needs to create the idle thread friend void startKernel(); //Needs threadLauncher - friend void miosix_private::initCtxsave(unsigned int *ctxsave, - void *(*pc)(void *), unsigned int *sp, void *argv); + friend void miosix_private::initCtxsave(unsigned int *, void *(*)(void *), + unsigned int *, void *); //Needs access to priority, savedPriority, mutexLocked and flags. friend class Mutex; //Needs access to flags @@ -1062,13 +1062,13 @@ private: //Needs access to flags, schedData friend class EDFScheduler; //Needs access to flags - friend int ::pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); + friend int ::pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *); //Needs access to flags - friend int ::pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime); + friend int pthreadCondTimedWaitImpl(pthread_cond_t *, pthread_mutex_t *, long long); //Needs access to flags - friend int ::pthread_cond_signal(pthread_cond_t *cond); + friend int ::pthread_cond_signal(pthread_cond_t *); //Needs access to flags - friend int ::pthread_cond_broadcast(pthread_cond_t *cond); + friend int ::pthread_cond_broadcast(pthread_cond_t *); //Needs access to cppReent friend class CppReentrancyAccessor; #ifdef WITH_PROCESSES diff --git a/miosix/kernel/pthread.cpp b/miosix/kernel/pthread.cpp index 37446505..f91bfa80 100644 --- a/miosix/kernel/pthread.cpp +++ b/miosix/kernel/pthread.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010, 2011 by Terraneo Federico * + * Copyright (C) 2010-2023 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 * @@ -330,41 +330,7 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) { - auto *condList=reinterpret_cast<IntrusiveList<CondData>*>(cond); - - long long timeout=timespec2ll(abstime); - //Disallow absolute sleeps with negative or too low values, as the ns2tick() - //algorithm in TimeConversion can't handle negative values and may undeflow - //even with very low values due to a negative adjustOffsetNs. As an unlikely - //side effect, very shor sleeps done very early at boot will be extended. - timeout=std::max(timeout,100000LL); - FastInterruptDisableLock dLock; - Thread *p=Thread::IRQgetCurrentThread(); - CondData listItem; - listItem.thread=p; - condList->push_back(&listItem); //Putting this thread last on the list (lifo policy) - SleepData sleepData; - sleepData.p=p; - sleepData.wakeupTime=timeout; - IRQaddToSleepingList(&sleepData); //Putting this thread on the sleeping list too - p->flags.IRQsetCondWait(true); - - unsigned int depth=IRQdoMutexUnlockAllDepthLevels(mutex); - { - FastInterruptEnableLock eLock(dLock); - Thread::yield(); //Here the wait becomes effective - } - //Ensure that the thread is removed from both list, as it can be woken by - //either a signal/broadcast (that removes it from condList) or by - //IRQwakeThreads (that removes it from sleeping list). - bool removed=condList->removeFast(&listItem); - IRQremoveFromSleepingList(&sleepData); - - IRQdoMutexLockToDepth(mutex,dLock,depth); - - //If the thread was still in the cond variable list, it was woken up by a timeout - if(removed) return ETIMEDOUT; - return 0; + return pthreadCondTimedWaitImpl(cond,mutex,timespec2ll(abstime)); } int pthread_cond_signal(pthread_cond_t *cond) @@ -473,3 +439,44 @@ int pthread_once(pthread_once_t *once, void (*func)()) int pthread_setcancelstate(int state, int *oldstate) { return 0; } //Stub } //extern "C" + +namespace miosix { + +int pthreadCondTimedWaitImpl(pthread_cond_t *cond, pthread_mutex_t *mutex, long long absTime) +{ + auto *condList=reinterpret_cast<IntrusiveList<CondData>*>(cond); + + //Disallow absolute sleeps with negative or too low values, as the ns2tick() + //algorithm in TimeConversion can't handle negative values and may undeflow + //even with very low values due to a negative adjustOffsetNs. As an unlikely + //side effect, very shor sleeps done very early at boot will be extended. + absTime=std::max(absTime,100000LL); + FastInterruptDisableLock dLock; + Thread *p=Thread::IRQgetCurrentThread(); + CondData listItem; + listItem.thread=p; + condList->push_back(&listItem); //Putting this thread last on the list (lifo policy) + SleepData sleepData; + sleepData.p=p; + sleepData.wakeupTime=absTime; + IRQaddToSleepingList(&sleepData); //Putting this thread on the sleeping list too + p->flags.IRQsetCondWait(true); + + unsigned int depth=IRQdoMutexUnlockAllDepthLevels(mutex); + { + FastInterruptEnableLock eLock(dLock); + Thread::yield(); //Here the wait becomes effective + } + //Ensure that the thread is removed from both list, as it can be woken by + //either a signal/broadcast (that removes it from condList) or by + //IRQwakeThreads (that removes it from sleeping list). + bool removed=condList->removeFast(&listItem); + IRQremoveFromSleepingList(&sleepData); + + IRQdoMutexLockToDepth(mutex,dLock,depth); + + //If the thread was still in the cond variable list, it was woken up by a timeout + return removed ? ETIMEDOUT : 0; +} + +} //namespace miosix diff --git a/miosix/kernel/pthread_private.h b/miosix/kernel/pthread_private.h index 2dc4cd71..1c43e211 100644 --- a/miosix/kernel/pthread_private.h +++ b/miosix/kernel/pthread_private.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2011 by Terraneo Federico * + * Copyright (C) 2011-2023 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 * @@ -33,6 +33,7 @@ #include <pthread.h> #include "kernel.h" #include "intrusive.h" +#include "sync.h" namespace miosix { @@ -219,15 +220,6 @@ static inline unsigned int IRQdoMutexUnlockAllDepthLevels(pthread_mutex_t *mutex return result; } -/** - * \internal - * \struct CondData - * This struct is used to make a list of threads that are waiting on a condition - * variable. It is used by the kernel, and should not be used by end users. - */ -struct CondData : public IntrusiveListItem -{ - Thread *thread; ///<\internal Thread that is waiting -}; +int pthreadCondTimedWaitImpl(pthread_cond_t *cond, pthread_mutex_t *mutex, long long absTime); } //namespace miosix diff --git a/miosix/kernel/sync.cpp b/miosix/kernel/sync.cpp index ceb01c48..8a7d4256 100644 --- a/miosix/kernel/sync.cpp +++ b/miosix/kernel/sync.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2008, 2009, 2010, 2011 by Terraneo Federico * + * Copyright (C) 2008-2023 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 * @@ -24,7 +24,6 @@ * You should have received a copy of the GNU General Public License * * along with this program; if not, see <http://www.gnu.org/licenses/> * ***************************************************************************/ - //Miosix kernel #include "sync.h" #include "kernel.h" @@ -37,11 +36,14 @@ using namespace std; namespace miosix { +void IRQaddToSleepingList(SleepData *x); +void IRQremoveFromSleepingList(SleepData *x); + // // class Mutex // -Mutex::Mutex(Options opt): owner(0), next(0), waiting() +Mutex::Mutex(Options opt): owner(nullptr), next(nullptr), waiting() { recursiveDepth= opt==RECURSIVE ? 0 : -1; } @@ -49,12 +51,12 @@ Mutex::Mutex(Options opt): owner(0), next(0), waiting() void Mutex::PKlock(PauseKernelLock& dLock) { Thread *p=Thread::getCurrentThread(); - if(owner==0) + if(owner==nullptr) { owner=p; //Save original thread priority, if the thread has not yet locked //another mutex - if(owner->mutexLocked==0) owner->savedPriority=owner->getPriority(); + if(owner->mutexLocked==nullptr) owner->savedPriority=owner->getPriority(); //Add this mutex to the list of mutexes locked by owner this->next=owner->mutexLocked; owner->mutexLocked=this; @@ -79,7 +81,7 @@ void Mutex::PKlock(PauseKernelLock& dLock) push_heap(waiting.begin(),waiting.end(),l); //Handle priority inheritance - if(p->mutexWaiting!=0) errorHandler(UNEXPECTED); + if(p->mutexWaiting!=nullptr) errorHandler(UNEXPECTED); p->mutexWaiting=this; if (owner->getPriority().mutexLessOp(p->getPriority())) { @@ -87,7 +89,7 @@ void Mutex::PKlock(PauseKernelLock& dLock) for(;;) { Scheduler::PKsetPriority(walk,p->getPriority()); - if(walk->mutexWaiting==0) break; + if(walk->mutexWaiting==nullptr) break; make_heap(walk->mutexWaiting->waiting.begin(), walk->mutexWaiting->waiting.end(),l); walk=walk->mutexWaiting->owner; @@ -117,13 +119,13 @@ void Mutex::PKlock(PauseKernelLock& dLock) void Mutex::PKlockToDepth(PauseKernelLock& dLock, unsigned int depth) { Thread *p=Thread::getCurrentThread(); - if(owner==0) + if(owner==nullptr) { owner=p; if(recursiveDepth>=0) recursiveDepth=depth; //Save original thread priority, if the thread has not yet locked //another mutex - if(owner->mutexLocked==0) owner->savedPriority=owner->getPriority(); + if(owner->mutexLocked==nullptr) owner->savedPriority=owner->getPriority(); //Add this mutex to the list of mutexes locked by owner this->next=owner->mutexLocked; owner->mutexLocked=this; @@ -148,7 +150,7 @@ void Mutex::PKlockToDepth(PauseKernelLock& dLock, unsigned int depth) push_heap(waiting.begin(),waiting.end(),l); //Handle priority inheritance - if(p->mutexWaiting!=0) errorHandler(UNEXPECTED); + if(p->mutexWaiting!=nullptr) errorHandler(UNEXPECTED); p->mutexWaiting=this; if (owner->getPriority().mutexLessOp(p->getPriority())) { @@ -156,7 +158,7 @@ void Mutex::PKlockToDepth(PauseKernelLock& dLock, unsigned int depth) for(;;) { Scheduler::PKsetPriority(walk,p->getPriority()); - if(walk->mutexWaiting==0) break; + if(walk->mutexWaiting==nullptr) break; make_heap(walk->mutexWaiting->waiting.begin(), walk->mutexWaiting->waiting.end(),l); walk=walk->mutexWaiting->owner; @@ -187,12 +189,12 @@ void Mutex::PKlockToDepth(PauseKernelLock& dLock, unsigned int depth) bool Mutex::PKtryLock(PauseKernelLock& dLock) { Thread *p=Thread::getCurrentThread(); - if(owner==0) + if(owner==nullptr) { owner=p; //Save original thread priority, if the thread has not yet locked //another mutex - if(owner->mutexLocked==0) owner->savedPriority=owner->getPriority(); + if(owner->mutexLocked==nullptr) owner->savedPriority=owner->getPriority(); //Add this mutex to the list of mutexes locked by owner this->next=owner->mutexLocked; owner->mutexLocked=this; @@ -226,7 +228,7 @@ bool Mutex::PKunlock(PauseKernelLock& dLock) for(;;) { //this Mutex not in owner's list? impossible - if(walk->next==0) errorHandler(UNEXPECTED); + if(walk->next==nullptr) errorHandler(UNEXPECTED); if(walk->next==this) { walk->next=walk->next->next; @@ -237,7 +239,7 @@ bool Mutex::PKunlock(PauseKernelLock& dLock) } //Handle priority inheritance - if(owner->mutexLocked==0) + if(owner->mutexLocked==nullptr) { //Not locking any other mutex if(owner->savedPriority!=owner->getPriority()) @@ -247,7 +249,7 @@ bool Mutex::PKunlock(PauseKernelLock& dLock) //Calculate new priority of thread, which is //max(savedPriority, inheritedPriority) Mutex *walk=owner->mutexLocked; - while(walk!=0) + while(walk!=nullptr) { if(walk->waiting.empty()==false) if (pr.mutexLessOp(walk->waiting.front()->getPriority())) @@ -266,9 +268,9 @@ bool Mutex::PKunlock(PauseKernelLock& dLock) pop_heap(waiting.begin(),waiting.end(),l); waiting.pop_back(); if(owner->mutexWaiting!=this) errorHandler(UNEXPECTED); - owner->mutexWaiting=0; + owner->mutexWaiting=nullptr; owner->PKwakeup(); - if(owner->mutexLocked==0) owner->savedPriority=owner->getPriority(); + if(owner->mutexLocked==nullptr) owner->savedPriority=owner->getPriority(); //Add this mutex to the list of mutexes locked by owner this->next=owner->mutexLocked; owner->mutexLocked=this; @@ -278,7 +280,7 @@ bool Mutex::PKunlock(PauseKernelLock& dLock) Scheduler::PKsetPriority(owner,waiting.front()->getPriority()); return p->getPriority().mutexLessOp(owner->getPriority()); } else { - owner=0; //No threads waiting + owner=nullptr; //No threads waiting std::vector<Thread *>().swap(waiting); //Save some RAM return false; } @@ -298,7 +300,7 @@ unsigned int Mutex::PKunlockAllDepthLevels(PauseKernelLock& dLock) for(;;) { //this Mutex not in owner's list? impossible - if(walk->next==0) errorHandler(UNEXPECTED); + if(walk->next==nullptr) errorHandler(UNEXPECTED); if(walk->next==this) { walk->next=walk->next->next; @@ -309,7 +311,7 @@ unsigned int Mutex::PKunlockAllDepthLevels(PauseKernelLock& dLock) } //Handle priority inheritance - if(owner->mutexLocked==0) + if(owner->mutexLocked==nullptr) { //Not locking any other mutex if(owner->savedPriority!=owner->getPriority()) @@ -319,7 +321,7 @@ unsigned int Mutex::PKunlockAllDepthLevels(PauseKernelLock& dLock) //Calculate new priority of thread, which is //max(savedPriority, inheritedPriority) Mutex *walk=owner->mutexLocked; - while(walk!=0) + while(walk!=nullptr) { if(walk->waiting.empty()==false) if (pr.mutexLessOp(walk->waiting.front()->getPriority())) @@ -338,9 +340,9 @@ unsigned int Mutex::PKunlockAllDepthLevels(PauseKernelLock& dLock) pop_heap(waiting.begin(),waiting.end(),l); waiting.pop_back(); if(owner->mutexWaiting!=this) errorHandler(UNEXPECTED); - owner->mutexWaiting=0; + owner->mutexWaiting=nullptr; owner->PKwakeup(); - if(owner->mutexLocked==0) owner->savedPriority=owner->getPriority(); + if(owner->mutexLocked==nullptr) owner->savedPriority=owner->getPriority(); //Add this mutex to the list of mutexes locked by owner this->next=owner->mutexLocked; owner->mutexLocked=this; @@ -349,7 +351,7 @@ unsigned int Mutex::PKunlockAllDepthLevels(PauseKernelLock& dLock) owner->getPriority().mutexLessOp(waiting.front()->getPriority())) Scheduler::PKsetPriority(owner,waiting.front()->getPriority()); } else { - owner=0; //No threads waiting + owner=nullptr; //No threads waiting std::vector<Thread *>().swap(waiting); //Save some RAM } @@ -363,27 +365,21 @@ unsigned int Mutex::PKunlockAllDepthLevels(PauseKernelLock& dLock) // class ConditionVariable // -ConditionVariable::ConditionVariable(): first(0), last(0) {} +//Memory layout must be kept in sync with pthread_cond, see wait(FastMutex& m) +static_assert(sizeof(ConditionVariable)==sizeof(pthread_cond_t),""); void ConditionVariable::wait(Mutex& m) { PauseKernelLock dLock; - - WaitingData w; - w.p=Thread::getCurrentThread(); - w.next=0; - //Add entry to tail of list - if(first==0) - { - first=last=&w; - } else { - last->next=&w; - last=&w; - } + Thread *t=Thread::getCurrentThread(); + CondData listItem; + listItem.thread=t; + condList.push_back(&listItem); //Add entry to tail of list + //Unlock mutex and wait { FastInterruptDisableLock l; - w.p->flags.IRQsetCondWait(true); + t->flags.IRQsetCondWait(true); } unsigned int depth=m.PKunlockAllDepthLevels(dLock); @@ -394,30 +390,55 @@ void ConditionVariable::wait(Mutex& m) m.PKlockToDepth(dLock,depth); } -void ConditionVariable::wait(FastMutex& m) +TimedWaitResult ConditionVariable::timedWait(Mutex& m, long long absTime) { - FastInterruptDisableLock dLock; - - WaitingData w; - w.p=Thread::getCurrentThread(); - w.next=0; - //Add entry to tail of list - if(first==0) + //Disallow absolute sleeps with negative or too low values, as the ns2tick() + //algorithm in TimeConversion can't handle negative values and may undeflow + //even with very low values due to a negative adjustOffsetNs. As an unlikely + //side effect, very shor sleeps done very early at boot will be extended. + absTime=std::max(absTime,100000LL); + + PauseKernelLock dLock; + Thread *t=Thread::getCurrentThread(); + CondData listItem; + listItem.thread=t; + condList.push_back(&listItem); //Add entry to tail of list + SleepData sleepData; + sleepData.p=t; + sleepData.wakeupTime=absTime; + + //Unlock mutex and wait { - first=last=&w; - } else { - last->next=&w; - last=&w; + FastInterruptDisableLock l; + IRQaddToSleepingList(&sleepData); //Putting this thread on the sleeping list too + t->flags.IRQsetCondWait(true); } - //Unlock mutex and wait - w.p->flags.IRQsetCondWait(true); - unsigned int depth=IRQdoMutexUnlockAllDepthLevels(m.get()); + unsigned int depth=m.PKunlockAllDepthLevels(dLock); { - FastInterruptEnableLock eLock(dLock); + RestartKernelLock eLock(dLock); Thread::yield(); //Here the wait becomes effective } - IRQdoMutexLockToDepth(m.get(),dLock,depth); + + //Ensure that the thread is removed from both list, as it can be woken by + //either a signal/broadcast (that removes it from condList) or by + //IRQwakeThreads (that removes it from sleeping list). + bool removed=condList.removeFast(&listItem); + { + FastInterruptDisableLock l; + IRQremoveFromSleepingList(&sleepData); + } + + m.PKlockToDepth(dLock,depth); + + //If the thread was still in the cond variable list, it was woken up by a timeout + return removed ? TimedWaitResult::Timeout : TimedWaitResult::NoTimeout; +} + +TimedWaitResult ConditionVariable::timedWait(FastMutex& m, long long absTime) +{ + return pthreadCondTimedWaitImpl(reinterpret_cast<pthread_cond_t*>(this), + m.get(),absTime)==ETIMEDOUT ? TimedWaitResult::Timeout : TimedWaitResult::NoTimeout; } void ConditionVariable::signal() @@ -428,14 +449,15 @@ void ConditionVariable::signal() //that can only be called with irq disabled, othrwise we would use //PauseKernelLock FastInterruptDisableLock lock; - if(first==0) return; - //Wakeup - first->p->flags.IRQsetCondWait(false); + if(condList.empty()) return; + //Remove from list and wakeup + Thread *t=condList.front()->thread; + condList.pop_front(); + t->flags.IRQsetCondWait(false); + t->flags.IRQsetSleep(false); //Needed due to timedwait //Check for priority issues - if(Thread::IRQgetCurrentThread()->IRQgetPriority() < - first->p->IRQgetPriority()) hppw=true; - //Remove from list - first=first->next; + if(t->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority()) + hppw=true; } //If the woken thread has higher priority than our priority, yield if(hppw) Thread::yield(); @@ -449,15 +471,16 @@ void ConditionVariable::broadcast() //that can only be called with irq disabled, othrwise we would use //PauseKernelLock FastInterruptDisableLock lock; - while(first!=0) + while(!condList.empty()) { - //Wakeup - first->p->flags.IRQsetCondWait(false); + //Remove from list and wakeup + Thread *t=condList.front()->thread; + condList.pop_front(); + t->flags.IRQsetCondWait(false); + t->flags.IRQsetSleep(false); //Needed due to timedwait //Check for priority issues - if(Thread::IRQgetCurrentThread()->IRQgetPriority() < - first->p->IRQgetPriority()) hppw=true; - //Remove from list - first=first->next; + if(t->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority()) + hppw=true; } } //If at least one of the woken thread has higher priority than our priority, diff --git a/miosix/kernel/sync.h b/miosix/kernel/sync.h index dfc2fd52..7bb97449 100644 --- a/miosix/kernel/sync.h +++ b/miosix/kernel/sync.h @@ -1,6 +1,5 @@ /*************************************************************************** - * Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 * - * by Terraneo Federico * + * Copyright (C) 2008-2023 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 * @@ -25,12 +24,11 @@ * You should have received a copy of the GNU General Public License * * along with this program; if not, see <http://www.gnu.org/licenses/> * ***************************************************************************/ - //Miosix kernel -#ifndef SYNC_H -#define SYNC_H +#pragma once #include "kernel.h" +#include "intrusive.h" #include <vector> namespace miosix { @@ -68,7 +66,7 @@ public: pthread_mutexattr_settype(&temp,PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&impl,&temp); pthread_mutexattr_destroy(&temp); - } else pthread_mutex_init(&impl,NULL); + } else pthread_mutex_init(&impl,nullptr); } /** @@ -386,6 +384,26 @@ private: T& mutex;///< Reference to locked mutex }; +/** + * \internal + * \struct CondData + * This struct is used to make a list of threads that are waiting on a condition + * variable. It is used by the kernel, and should not be used by end users. + */ +struct CondData : public IntrusiveListItem +{ + Thread *thread; ///<\internal Thread that is waiting +}; + +/** + * Possible return values of timedWait + */ +enum class TimedWaitResult +{ + NoTimeout, + Timeout +}; + /** * A condition variable class for thread synchronization, available from * Miosix 1.53.<br> @@ -402,7 +420,7 @@ public: /** * Constructor, initializes the ConditionVariable. */ - ConditionVariable(); + ConditionVariable() {} /** * Unlock the mutex and wait. @@ -416,6 +434,20 @@ public: wait(l.get()); } + /** + * Unlock the mutex and wait until woken up or timeout occurs. + * If more threads call wait() they must do so specifying the same mutex, + * otherwise the behaviour is undefined. + * \param l A Lock instance that locked a Mutex + * \param absTime absolute timeout time in nanoseconds + * \return whether the return was due to a timout or wakeup + */ + template<typename T> + TimedWaitResult wait(Lock<T>& l, long long absTime) + { + return timedWait(l.get()); + } + /** * Unlock the Mutex and wait. * If more threads call wait() they must do so specifying the same mutex, @@ -430,7 +462,32 @@ public: * otherwise the behaviour is undefined. * \param m a locked Mutex */ - void wait(FastMutex& m); + void wait(FastMutex& m) + { + //Memory layout of ConditionVariable is the same of pthread_cond_t and + //the algorithm would be exactly the same + pthread_cond_wait(reinterpret_cast<pthread_cond_t*>(this),m.get()); + } + + /** + * Unlock the Mutex and wait until woken up or timeout occurs. + * If more threads call wait() they must do so specifying the same mutex, + * otherwise the behaviour is undefined. + * \param m a locked Mutex + * \param absTime absolute timeout time in nanoseconds + * \return whether the return was due to a timout or wakeup + */ + TimedWaitResult timedWait(Mutex& m, long long absTime); + + /** + * Unlock the FastMutex and wait until woken up or timeout occurs. + * If more threads call wait() they must do so specifying the same mutex, + * otherwise the behaviour is undefined. + * \param m a locked Mutex + * \param absTime absolute timeout time in nanoseconds + * \return whether the return was due to a timout or wakeup + */ + TimedWaitResult timedWait(FastMutex& m, long long absTime); /** * Wakeup one waiting thread. @@ -448,19 +505,8 @@ private: ConditionVariable(const ConditionVariable& ); ConditionVariable& operator= (const ConditionVariable& ); - /** - * \internal - * \struct WaitingData - * This struct is used to make a list of waiting threads. - */ - struct WaitingData - { - Thread *p;///<\internal Thread that is waiting - WaitingData *next;///<\internal Next thread in the list - }; - - WaitingData *first;///<Pointer to first element of waiting fifo - WaitingData *last;///<Pointer to last element of waiting fifo + //Memory layout must be kept in sync with pthread_cond, see wait(FastMutex& m) + IntrusiveList<CondData> condList; }; /** @@ -468,5 +514,3 @@ private: */ } //namespace miosix - -#endif //SYNC_H -- GitLab