diff --git a/miosix/kernel/kernel.h b/miosix/kernel/kernel.h
index c7eb36af6c19bf1573bb427daa9eac45afba0d37..7c8c054f81fffea42c37a9b70e24560c167c4661 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 3744650510305f5f0a6831b3563da416dc6049b5..f91bfa805ba9de39085a62668c1f8ad8f467aacd 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 2dc4cd7172a436e14ade9cf2f27ea36bb882151e..1c43e211c10a2f7e4e6b2b396ffa305a71c533e2 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 ceb01c48cb43be861795f30800dea7f6b3c31a10..8a7d425666776393080047dceac8ca258249cf2d 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 dfc2fd52411a85f43e233f095315b34a57ea75d5..7bb97449a6ca33cfa48e996266c204cecf423e68 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