From 81b3f57afb35702279665e11730f5b1cdfcb0e35 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niccol=C3=B2=20Betto?= <niccolo.betto@skywarder.eu>
Date: Mon, 17 Jul 2023 15:50:44 +0000
Subject: [PATCH] Added timed wait feature

---
 miosix/CMakeLists.txt       |   1 +
 miosix/Makefile             |   1 +
 miosix/kernel/intrusive.cpp | 412 ++++++++++++++++++++++++++++++++++++
 miosix/kernel/intrusive.h   | 307 +++++++++++++++++++++++++--
 miosix/kernel/kernel.cpp    | 142 +++++++++----
 miosix/kernel/kernel.h      | 221 +++++++++++++++++--
 miosix/kernel/sync.cpp      |  78 +++----
 miosix/kernel/sync.h        |  23 +-
 8 files changed, 1049 insertions(+), 136 deletions(-)
 create mode 100644 miosix/kernel/intrusive.cpp

diff --git a/miosix/CMakeLists.txt b/miosix/CMakeLists.txt
index df1d0d4d..3e820022 100644
--- a/miosix/CMakeLists.txt
+++ b/miosix/CMakeLists.txt
@@ -68,6 +68,7 @@ foreach(OPT_BOARD ${BOARDS})
         kernel/process_pool.cpp
         kernel/timeconversion.cpp
         kernel/SystemMap.cpp
+        kernel/intrusive.cpp
         kernel/scheduler/priority/priority_scheduler.cpp
         kernel/scheduler/control/control_scheduler.cpp
         kernel/scheduler/edf/edf_scheduler.cpp
diff --git a/miosix/Makefile b/miosix/Makefile
index afb5aff8..6653d061 100644
--- a/miosix/Makefile
+++ b/miosix/Makefile
@@ -23,6 +23,7 @@ kernel/process.cpp                                                         \
 kernel/process_pool.cpp                                                    \
 kernel/timeconversion.cpp                                                  \
 kernel/SystemMap.cpp                                                       \
+kernel/intrusive.cpp                                                       \
 kernel/scheduler/priority/priority_scheduler.cpp                           \
 kernel/scheduler/control/control_scheduler.cpp                             \
 kernel/scheduler/edf/edf_scheduler.cpp                                     \
diff --git a/miosix/kernel/intrusive.cpp b/miosix/kernel/intrusive.cpp
new file mode 100644
index 00000000..213fcb30
--- /dev/null
+++ b/miosix/kernel/intrusive.cpp
@@ -0,0 +1,412 @@
+/***************************************************************************
+ *   Copyright (C) 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  *
+ *   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 TEST_ALGORITHM
+
+#include "intrusive.h"
+
+#else //TEST_ALGORITHM
+
+#include <iostream>
+#include <cassert>
+
+// Unused stubs as the test code only tests IntrusiveList
+inline int atomicSwap(volatile int*, int) { return 0; }
+void *atomicFetchAndIncrement(void *const volatile*, int, int) { return nullptr; }
+
+//C++ glassbox testing trick
+#define private public
+#define protected public
+#include "intrusive.h"
+#undef private
+#undef public
+
+using namespace std;
+using namespace miosix;
+
+#endif //TEST_ALGORITHM
+
+namespace miosix {
+
+//
+// class IntrusiveListBase
+//
+
+void IntrusiveListBase::push_back(IntrusiveListItem *item)
+{
+    #ifdef INTRUSIVE_LIST_ERROR_CHECK
+    if((head!=nullptr) ^ (tail!=nullptr)) fail();
+    if(!empty() && head==tail && (head->prev || head->next)) fail();
+    if(item->prev!=nullptr || item->next!=nullptr) fail();
+    #endif //INTRUSIVE_LIST_ERROR_CHECK
+    if(empty()) head=item;
+    else {
+        item->prev=tail;
+        tail->next=item;
+    }
+    tail=item;
+}
+
+void IntrusiveListBase::pop_back()
+{
+    #ifdef INTRUSIVE_LIST_ERROR_CHECK
+    if(head==nullptr || tail==nullptr) fail();
+    if(!empty() && head==tail && (head->prev || head->next)) fail();
+    #endif //INTRUSIVE_LIST_ERROR_CHECK
+    IntrusiveListItem *removedItem=tail;
+    tail=removedItem->prev;
+    if(tail!=nullptr)
+    {
+        tail->next=nullptr;
+        removedItem->prev=nullptr;
+    } else head=nullptr;
+}
+
+void IntrusiveListBase::push_front(IntrusiveListItem *item)
+{
+    #ifdef INTRUSIVE_LIST_ERROR_CHECK
+    if((head!=nullptr) ^ (tail!=nullptr)) fail();
+    if(!empty() && head==tail && (head->prev || head->next)) fail();
+    if(item->prev!=nullptr || item->next!=nullptr) fail();
+    #endif //INTRUSIVE_LIST_ERROR_CHECK
+    if(empty()) tail=item;
+    else {
+        head->prev=item;
+        item->next=head;
+    }
+    head=item;
+}
+
+void IntrusiveListBase::pop_front()
+{
+    #ifdef INTRUSIVE_LIST_ERROR_CHECK
+    if(head==nullptr || tail==nullptr) fail();
+    if(!empty() && head==tail && (head->prev || head->next)) fail();
+    #endif //INTRUSIVE_LIST_ERROR_CHECK
+    IntrusiveListItem *removedItem=head;
+    head=removedItem->next;
+    if(head!=nullptr)
+    {
+        head->prev=nullptr;
+        removedItem->next=nullptr;
+    } else tail=nullptr;
+}
+
+void IntrusiveListBase::insert(IntrusiveListItem *cur, IntrusiveListItem *item)
+{
+    #ifdef INTRUSIVE_LIST_ERROR_CHECK
+    if((head!=nullptr) ^ (tail!=nullptr)) fail();
+    if(!empty() && head==tail && (head->prev || head->next)) fail();
+    if(cur!=nullptr)
+    {
+        if(cur->prev==nullptr && cur!=head) fail();
+        if(cur->next==nullptr && cur!=tail) fail();
+    }
+    if(item->prev!=nullptr || item->next!=nullptr) fail();
+    #endif //INTRUSIVE_LIST_ERROR_CHECK
+    item->next=cur;
+    if(cur!=nullptr)
+    {
+        item->prev=cur->prev;
+        cur->prev=item;
+    } else {
+        item->prev=tail;
+        tail=item;
+    }
+    if(item->prev!=nullptr) item->prev->next=item;
+    else head=item;
+}
+
+IntrusiveListItem *IntrusiveListBase::erase(IntrusiveListItem *cur)
+{
+    #ifdef INTRUSIVE_LIST_ERROR_CHECK
+    if(head==nullptr || tail==nullptr) fail();
+    if(!empty() && head==tail && (head->prev || head->next)) fail();
+    if(cur==nullptr) fail();
+    if(cur->prev==nullptr && cur!=head) fail();
+    if(cur->next==nullptr && cur!=tail) fail();
+    #endif //INTRUSIVE_LIST_ERROR_CHECK
+    if(cur->prev!=nullptr) cur->prev->next=cur->next;
+    else head=cur->next;
+    if(cur->next!=nullptr) cur->next->prev=cur->prev;
+    else tail=cur->prev;
+    auto result=cur->next;
+    cur->prev=nullptr;
+    cur->next=nullptr;
+    return result;
+}
+
+#ifdef INTRUSIVE_LIST_ERROR_CHECK
+#warning "INTRUSIVE_LIST_ERROR_CHECK should not be enabled in release builds"
+void IntrusiveListBase::fail()
+{
+    #ifndef TEST_ALGORITHM
+    errorHandler(UNEXPECTED);
+    #else //TEST_ALGORITHM
+    assert(false);
+    #endif //TEST_ALGORITHM
+}
+#endif //INTRUSIVE_LIST_ERROR_CHECK
+
+} //namespace miosix
+
+//Testsuite for IntrusiveList. Compile with:
+//g++ -DTEST_ALGORITHM -DINTRUSIVE_LIST_ERROR_CHECK -fsanitize=address -m32
+//    -std=c++14 -Wall -O2 -o test intrusive.cpp; ./test
+#ifdef TEST_ALGORITHM
+
+void emptyCheck(IntrusiveListItem& x)
+{
+    //Glass box check
+    assert(x.next==nullptr); assert(x.prev==nullptr);
+}
+
+void emptyCheck(IntrusiveList<IntrusiveListItem>& list)
+{
+    //Black box check
+    assert(list.empty());
+    assert(list.begin()==list.end());
+    //Glass box check
+    assert(list.head==nullptr);
+    assert(list.tail==nullptr);
+}
+
+void oneItemCheck(IntrusiveList<IntrusiveListItem>& list, IntrusiveListItem& a)
+{
+    IntrusiveList<IntrusiveListItem>::iterator it;
+    //Black box check
+    assert(list.empty()==false);
+    assert(list.front()==&a);
+    assert(list.back()==&a);
+    assert(list.begin()!=list.end());
+    assert(*list.begin()==&a);
+    assert(++list.begin()==list.end());
+    it=list.begin(); it++; assert(it==list.end());
+    assert(--list.end()==list.begin());
+    it=list.end(); it--; assert(it==list.begin());
+    //Glass box check
+    assert(list.head==&a);
+    assert(list.tail==&a);
+    assert(a.prev==nullptr);
+    assert(a.next==nullptr);
+}
+
+void twoItemCheck(IntrusiveList<IntrusiveListItem>& list, IntrusiveListItem& a,
+                  IntrusiveListItem& b)
+{
+    IntrusiveList<IntrusiveListItem>::iterator it;
+    //Black box check
+    assert(list.empty()==false);
+    assert(list.front()==&a);
+    assert(list.back()==&b);
+    assert(list.begin()!=list.end());
+    it=list.begin();
+    assert(*it++==&a);
+    assert(*it++==&b);
+    assert(it==list.end());
+    it=list.begin();
+    assert(*it==&a);
+    ++it;
+    assert(*it==&b);
+    ++it;
+    assert(it==list.end());
+    it=list.end();
+    it--;
+    assert(*it==&b);
+    it--;
+    assert(*it==&a);
+    assert(it==list.begin());
+    it=list.end();
+    assert(*--it==&b);
+    assert(*--it==&a);
+    assert(it==list.begin());
+    //Glass box check
+    assert(list.head==&a);
+    assert(list.tail==&b);
+    assert(a.prev==nullptr);
+    assert(a.next==&b);
+    assert(b.prev==&a);
+    assert(b.next==nullptr);
+}
+
+void threeItemCheck(IntrusiveList<IntrusiveListItem>& list, IntrusiveListItem& a,
+                  IntrusiveListItem& b, IntrusiveListItem& c)
+{
+    IntrusiveList<IntrusiveListItem>::iterator it;
+    //Black box check
+    assert(list.empty()==false);
+    assert(list.front()==&a);
+    assert(list.back()==&c);
+    assert(list.begin()!=list.end());
+    it=list.begin();
+    assert(*it++==&a);
+    assert(*it++==&b);
+    assert(*it++==&c);
+    assert(it==list.end());
+    it=list.begin();
+    assert(*it==&a);
+    ++it;
+    assert(*it==&b);
+    ++it;
+    assert(*it==&c);
+    ++it;
+    assert(it==list.end());
+    it=list.end();
+    it--;
+    assert(*it==&c);
+    it--;
+    assert(*it==&b);
+    it--;
+    assert(*it==&a);
+    assert(it==list.begin());
+    it=list.end();
+    assert(*--it==&c);
+    assert(*--it==&b);
+    assert(*--it==&a);
+    assert(it==list.begin());
+    //Glass box check
+    assert(list.head==&a);
+    assert(list.tail==&c);
+    assert(a.prev==nullptr);
+    assert(a.next==&b);
+    assert(b.prev==&a);
+    assert(b.next==&c);
+    assert(c.prev==&b);
+    assert(c.next==nullptr);
+}
+
+int main()
+{
+    IntrusiveListItem a,b,c;
+    IntrusiveList<IntrusiveListItem> list;
+    emptyCheck(a);
+    emptyCheck(b);
+    emptyCheck(c);
+    emptyCheck(list);
+
+    //
+    // Testing push_back / pop_back
+    //
+    list.push_back(&a);
+    oneItemCheck(list,a);
+    list.push_back(&b);
+    twoItemCheck(list,a,b);
+    list.pop_back();
+    oneItemCheck(list,a);
+    emptyCheck(b);
+    list.pop_back();
+    emptyCheck(list);
+    emptyCheck(a);
+
+    //
+    // Testing push_front / pop_front
+    //
+    list.push_front(&a);
+    oneItemCheck(list,a);
+    list.push_front(&b);
+    twoItemCheck(list,b,a);
+    list.pop_front();
+    oneItemCheck(list,a);
+    emptyCheck(b);
+    list.pop_front();
+    emptyCheck(list);
+    emptyCheck(a);
+
+    //
+    // Testing insert / erase
+    //
+    list.insert(list.end(),&a);
+    oneItemCheck(list,a);
+    list.insert(list.end(),&b);
+    twoItemCheck(list,a,b);
+    list.erase(++list.begin()); //Erase second item first
+    oneItemCheck(list,a);
+    emptyCheck(b);
+    list.erase(list.begin());   //Erase only item
+    emptyCheck(list);
+    emptyCheck(a);
+    list.insert(list.begin(),&a);
+    oneItemCheck(list,a);
+    list.insert(list.begin(),&b);
+    twoItemCheck(list,b,a);
+    list.erase(list.begin());   //Erase first item first
+    oneItemCheck(list,a);
+    emptyCheck(b);
+    list.erase(list.begin());   //Erase only item
+    emptyCheck(list);
+    emptyCheck(a);
+    list.insert(list.end(),&a);
+    oneItemCheck(list,a);
+    list.insert(list.end(),&c);
+    twoItemCheck(list,a,c);
+    list.insert(++list.begin(),&b); //Insert in the middle
+    threeItemCheck(list,a,b,c);
+    list.erase(++list.begin());     //Erase in the middle
+    twoItemCheck(list,a,c);
+    emptyCheck(b);
+    list.erase(list.begin());
+    oneItemCheck(list,c);
+    emptyCheck(a);
+    list.erase(list.begin());
+    emptyCheck(list);
+    emptyCheck(c);
+
+    //
+    // Testing removeFast
+    //
+    assert(list.removeFast(&a)==false); //Not present, list empty
+    emptyCheck(list);
+    emptyCheck(a);
+    list.push_front(&a);
+    assert(list.removeFast(&b)==false); //Not present, list not empty
+    oneItemCheck(list,a);
+    emptyCheck(b);
+    assert(list.removeFast(&a)==true); //Present, only element
+    emptyCheck(list);
+    emptyCheck(a);
+    list.push_front(&c);
+    list.push_front(&b);
+    list.push_front(&a);
+    assert(list.removeFast(&a)==true); //Present, at list head
+    twoItemCheck(list,b,c);
+    emptyCheck(a);
+    list.push_front(&a);
+    assert(list.removeFast(&b)==true); //Present, at in the middle
+    twoItemCheck(list,a,c);
+    emptyCheck(b);
+    assert(list.removeFast(&c)==true); //Present, at list tail
+    oneItemCheck(list,a);
+    emptyCheck(c);
+    list.pop_front(); //Just to end with empty list
+    emptyCheck(list);
+    emptyCheck(a);
+
+    cout<<"Test passed"<<endl;
+    return 0;
+}
+
+#endif //TEST_ALGORITHM
diff --git a/miosix/kernel/intrusive.h b/miosix/kernel/intrusive.h
index 54442f5d..298b6071 100644
--- a/miosix/kernel/intrusive.h
+++ b/miosix/kernel/intrusive.h
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2013 by Terraneo Federico                               *
+ *   Copyright (C) 2013-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,17 +25,19 @@
  *   along with this program; if not, see <http://www.gnu.org/licenses/>   *
  ***************************************************************************/
 
-#ifndef INTRUSIVE_H
-#define INTRUSIVE_H
+#pragma once
 
 #include <ostream>
 #include <cstddef>
 #include <cassert>
+#include <type_traits>
+#ifndef TEST_ALGORITHM
 #include "interfaces/atomic_ops.h"
+#include "error.h"
+#endif //TEST_ALGORITHM
 
-#if __cplusplus > 199711L
-#include <type_traits>
-#endif // c++11
+//Only enable when testing code that uses IntrusiveList
+//#define INTRUSIVE_LIST_ERROR_CHECK
 
 namespace miosix {
 
@@ -181,7 +183,7 @@ public:
     /**
      * Default constructor
      */
-    intrusive_ref_ptr() : object(0) {}
+    intrusive_ref_ptr() : object(nullptr) {}
     
     /**
      * Constructor, with raw pointer
@@ -267,7 +269,7 @@ public:
      * \return a pointer to the managed object
      */
     T *operator->() const { return object; }
-    
+
     //Safe bool idiom
     struct SafeBoolStruct { void* b; };
     typedef void* SafeBoolStruct::* SafeBool;
@@ -279,7 +281,15 @@ public:
     {
         return object==0 ? 0 : &SafeBoolStruct::b;
     }
-    
+
+    /**
+     * \return true if the object contains a callback
+     */
+    explicit operator bool() const
+    {
+        return object!=nullptr;
+    }
+
     /**
      * Swap the managed object with another intrusive_ref_ptr
      * \param rhs the other smart pointer
@@ -294,9 +304,9 @@ public:
     void reset()
     {
         if(decrementRefCount()) delete object;
-        // Object needs to be set to 0 regardless
+        // Object needs to be set to nullptr regardless
         // of whether the object is deleted
-        object=0;
+        object=nullptr;
     }
     
     /**
@@ -349,7 +359,7 @@ private:
      */
     bool decrementRefCount()
     {
-        if(object==0) return false;
+        if(object==nullptr) return false;
         return atomicAddExchange(&object->intrusive.referenceCount,-1)==1;
     }
 
@@ -395,7 +405,7 @@ intrusive_ref_ptr<T>& intrusive_ref_ptr<T>::operator= (T* o)
 template<typename T>
 intrusive_ref_ptr<T> intrusive_ref_ptr<T>::atomic_load() const
 {
-    intrusive_ref_ptr<T> result; // This gets initialized with 0
+    intrusive_ref_ptr<T> result; // This gets initialized with nullptr
     
     // According to the C++ standard, this causes undefined behaviour if
     // T has virtual functions, but GCC (and clang) have an implementation
@@ -442,7 +452,7 @@ intrusive_ref_ptr<T> intrusive_ref_ptr<T>::atomic_exchange(
     volatile int *objectAddrInt=reinterpret_cast<volatile int*>(&object);
     temp=reinterpret_cast<T*>(atomicSwap(objectAddrInt,tempInt));
     
-    intrusive_ref_ptr<T> result; // This gets initialized with 0
+    intrusive_ref_ptr<T> result; // This gets initialized with nullptr
     // This does not increment referenceCount, as the pointer was swapped
     result.object=temp;
     return result;
@@ -595,7 +605,7 @@ intrusive_ref_ptr<T> const_pointer_cast(const intrusive_ref_ptr<U>& r)
 template<typename T>
 intrusive_ref_ptr<T> atomic_load(const intrusive_ref_ptr<T> *p)
 {
-    if(p==0) return intrusive_ref_ptr<T>();
+    if(p==nullptr) return intrusive_ref_ptr<T>();
     return p->atomic_load();
 }
 
@@ -630,10 +640,271 @@ template<typename T>
 intrusive_ref_ptr<T> atomic_exchange(intrusive_ref_ptr<T> *p,
         intrusive_ref_ptr<T> r)
 {
-    if(p==0) return intrusive_ref_ptr<T>();
+    if(p==nullptr) return intrusive_ref_ptr<T>();
     return p->atomic_exchange(r);
 }
 
-} //namenpace miosix
+//Forward declarations
+class IntrusiveListBase;
+template<typename T>
+class IntrusiveList;
+
+/**
+ * Base class from which all items to be put in an IntrusiveList must derive,
+ * contains the next and prev pointer that create the list
+ */
+class IntrusiveListItem
+{
+private:
+    IntrusiveListItem *next=nullptr;
+    IntrusiveListItem *prev=nullptr;
+
+    friend class IntrusiveListBase;
+    template<typename T>
+    friend class IntrusiveList;
+};
+
+/**
+ * \internal
+ * Base class of IntrusiveList with the non-template-dependent part to improve
+ * code size when instantiationg multiple IntrusiveLists
+ */
+class IntrusiveListBase
+{
+protected:
+    IntrusiveListBase() : head(nullptr), tail(nullptr) {}
+
+    void push_back(IntrusiveListItem *item);
+
+    void pop_back();
+
+    void push_front(IntrusiveListItem *item);
+
+    void pop_front();
+
+    void insert(IntrusiveListItem *cur, IntrusiveListItem *item);
+
+    IntrusiveListItem *erase(IntrusiveListItem *cur);
+
+    IntrusiveListItem* front() { return head; }
+
+    IntrusiveListItem* back() { return tail; }
+
+    bool empty() const { return head==nullptr; }
+
+    #ifdef INTRUSIVE_LIST_ERROR_CHECK
+    static void fail();
+    #endif //INTRUSIVE_LIST_ERROR_CHECK
+
+private:
+    IntrusiveListItem *head;
+    IntrusiveListItem *tail;
+};
+
+/**
+ * A doubly linked list that only accepts objects that derive from
+ * IntrusiveListItem.
+ * 
+ * Compared to std::list, this class offers the guarantee that no dynamic memory
+ * allocation is performed. Differently from std::list, objects are not copied
+ * when put in the list, so this is a non-owning container. For this reason,
+ * this class unlike std::list accepts objects by pointer instead of reference
+ * in member functions like insert() or push_front(), and returns objects by
+ * pointer when dereferncing iterators or in member functions like front().
+ * The caller is thus responsible for managing the lifetime of objects put in
+ * this list.
+ */
+template<typename T>
+class IntrusiveList : private IntrusiveListBase
+{
+public:
+    /**
+     * Intrusive list iterator type
+     */
+    class iterator
+    {
+    public:
+        iterator() : list(nullptr), cur(nullptr) {}
+
+        T* operator*()
+        {
+            #ifdef INTRUSIVE_LIST_ERROR_CHECK
+            if(list==nullptr || cur==nullptr) IntrusiveListBase::fail();
+            #endif //INTRUSIVE_LIST_ERROR_CHECK
+            return static_cast<T*>(cur);
+        }
+
+        iterator operator++()
+        {
+            #ifdef INTRUSIVE_LIST_ERROR_CHECK
+            if(list==nullptr || cur==nullptr) IntrusiveListBase::fail();
+            #endif //INTRUSIVE_LIST_ERROR_CHECK
+            cur=cur->next; return *this;
+        }
+
+        iterator operator--()
+        {
+            #ifdef INTRUSIVE_LIST_ERROR_CHECK
+            if(list==nullptr || list->empty()) IntrusiveListBase::fail();
+            #endif //INTRUSIVE_LIST_ERROR_CHECK
+            if(cur!=nullptr) cur=cur->prev;
+            else cur=list->IntrusiveListBase::back(); //Special case: decrementing end()
+            return *this;
+        }
+
+        iterator operator++(int)
+        {
+            #ifdef INTRUSIVE_LIST_ERROR_CHECK
+            if(list==nullptr || cur==nullptr) IntrusiveListBase::fail();
+            #endif //INTRUSIVE_LIST_ERROR_CHECK
+            iterator result=*this;
+            cur=cur->next;
+            return result;
+        }
+
+        iterator operator--(int)
+        {
+            #ifdef INTRUSIVE_LIST_ERROR_CHECK
+            if(list==nullptr || list->empty()) IntrusiveListBase::fail();
+            #endif //INTRUSIVE_LIST_ERROR_CHECK
+            iterator result=*this;
+            if(cur!=nullptr) cur=cur->prev;
+            else cur=list->IntrusiveListBase::back(); //Special case: decrementing end()
+            return result;
+        }
+
+        bool operator==(const iterator& rhs) { return cur==rhs.cur; }
+        bool operator!=(const iterator& rhs) { return cur!=rhs.cur; }
+
+    private:
+        iterator(IntrusiveList<T> *list, IntrusiveListItem *cur)
+            : list(list), cur(cur) {}
+
+        IntrusiveList<T> *list;
+        IntrusiveListItem *cur;
+
+        friend class IntrusiveList<T>;
+    };
+    
+    /**
+     * Constructor, produces an empty list
+     */
+    IntrusiveList() {}
+
+    /**
+     * Disabled copy constructor and operator=
+     * Since intrusive lists do not store objects by value, and an item can
+     * only belong to at most one list, intrusive lists are not copyable.
+     */
+    IntrusiveList(const IntrusiveList&)=delete;
+    IntrusiveList& operator=(const IntrusiveList&)=delete;
+    
+    /**
+     * Adds item to the end of the list
+     * \param item item to add
+     */
+    void push_back(T *item) { IntrusiveListBase::push_back(item); }
+    
+    /**
+     * Removes the last element in the list
+     */
+    void pop_back() { IntrusiveListBase::pop_back(); }
+    
+    /**
+     * Adds item to the front of the list
+     * \param item item to add
+     */
+    void push_front(T *item) { IntrusiveListBase::push_front(item); }
+    
+    /**
+     * Removes the first item of the list
+     */
+    void pop_front() { IntrusiveListBase::pop_front(); }
+    
+    /**
+     * Inserts the given item before the position indicated by the iterator
+     * \param it position where to insert the item
+     * \param item item to insert
+     */
+    void insert(iterator it, T *item)
+    {
+        #ifdef INTRUSIVE_LIST_ERROR_CHECK
+        if(it.list!=this) fail();
+        #endif //INTRUSIVE_LIST_ERROR_CHECK
+        IntrusiveListItem *cur=it.cur; //Safe even if it==end() -> cur=nullptr
+        IntrusiveListBase::insert(cur,item);
+    }
+    
+    /**
+     * Removes the specified item from the list
+     * \param it iterator to the item to remove
+     * \return an iterator to the next item
+     */
+    iterator erase(iterator it)
+    {
+        #ifdef INTRUSIVE_LIST_ERROR_CHECK
+        if(it.list!=this) fail();
+        #endif //INTRUSIVE_LIST_ERROR_CHECK
+        IntrusiveListItem *cur=it.cur;
+        return iterator(this,IntrusiveListBase::erase(cur));
+    }
+
+    /**
+     * Nonportable version of std::list::remove that is O(1) since it relies on
+     * the list being intrusive
+     * NOTE: can ONLY be called if you are sure the item to remove is either not
+     * in any list (in this case, nothing is done) or is in the list it is being
+     * removed from. Trying to remove an item that is present in another list
+     * produces undefined bahavior.
+     * \param item item to remove, must not be nullptr
+     * \return true if the item was removed, false if the item was not present
+     * in the list
+     */
+    bool removeFast(T *item)
+    {
+        if(item->prev==nullptr && IntrusiveListBase::front()!=item) return false;
+        IntrusiveListBase::erase(item);
+        return true;
+    }
+    
+    /**
+     * \return an iterator to the first item
+     */
+    iterator begin() { return iterator(this,IntrusiveListBase::front()); }
+    
+    /**
+     * \return an iterator to the last item
+     */
+    iterator end() { return iterator(this,nullptr); }
+    
+    /**
+     * \return a pointer to the first item. List must not be empty
+     */
+    T* front()
+    {
+        auto result=IntrusiveListBase::front();
+        #ifdef INTRUSIVE_LIST_ERROR_CHECK
+        if(result==nullptr) fail();
+        #endif //INTRUSIVE_LIST_ERROR_CHECK
+        return static_cast<T*>(result);
+    }
+    
+    /**
+     * \return a pointer to the last item. List must not be empty
+     */
+    T* back()
+    {
+        auto result=IntrusiveListBase::back();
+        #ifdef INTRUSIVE_LIST_ERROR_CHECK
+        if(result==nullptr) fail();
+        #endif //INTRUSIVE_LIST_ERROR_CHECK
+        return static_cast<T*>(result);
+    }
+    
+    /**
+     * \return true if the list is empty
+     */
+    bool empty() const { return IntrusiveListBase::empty(); }
+};
 
-#endif //INTRUSIVE_H
+} //namespace miosix
diff --git a/miosix/kernel/kernel.cpp b/miosix/kernel/kernel.cpp
index 90a5ae67..2d65d5a5 100644
--- a/miosix/kernel/kernel.cpp
+++ b/miosix/kernel/kernel.cpp
@@ -62,7 +62,7 @@ volatile Thread *cur=NULL;///<\internal Thread currently running
 ///\internal True if there are threads in the DELETED status. Used by idle thread
 static volatile bool exist_deleted=false;
 
-static SleepData *sleeping_list=NULL;///<\internal list of sleeping threads
+static IntrusiveList<SleepData> sleeping_list;///<\internal list of sleeping threads
 
 static volatile long long tick=0;///<\internal Kernel tick
 
@@ -228,38 +228,26 @@ long long getTick()
 
 /**
  * \internal
- * Used by Thread::sleep() to add a thread to sleeping list. The list is sorted
- * by the wakeup_time field to reduce time required to wake threads during
- * context switch.
- * Also sets thread SLEEP_FLAG. It is labeled IRQ not because it is meant to be
- * used inside an IRQ, but because interrupts must be disabled prior to calling
- * this function.
+ * Used by Thread::sleep() to add a thread to
+ * sleeping list. The list is sorted by the wakeupTime field to reduce time
+ * required to wake threads during context switch.
+ * Interrupts must be disabled prior to calling this function.
  */
-void IRQaddToSleepingList(SleepData *x)
+static void IRQaddToSleepingList(SleepData *x)
 {
-    x->p->flags.IRQsetSleep(true);
-    if((sleeping_list==NULL)||(x->wakeup_time <= sleeping_list->wakeup_time))
+    if(sleeping_list.empty() || sleeping_list.front()->wakeupTime>=x->wakeupTime)
     {
-        x->next=sleeping_list;
-        sleeping_list=x;   
+        sleeping_list.push_front(x);
     } else {
-       SleepData *cur=sleeping_list;
-       for(;;)
-       {
-           if((cur->next==NULL)||(x->wakeup_time <= cur->next->wakeup_time))
-           {
-               x->next=cur->next;
-               cur->next=x;
-               break;
-           }
-           cur=cur->next;
-       }
+        auto it=sleeping_list.begin();
+        while(it!=sleeping_list.end() && (*it)->wakeupTime<x->wakeupTime) ++it;
+        sleeping_list.insert(it,x);
     }
 }
 
 /**
  * \internal
- * Called @ every tick to check if it's time to wake some thread.
+ * Called to check if it's time to wake some thread.
  * 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.
@@ -268,15 +256,18 @@ void IRQaddToSleepingList(SleepData *x)
 bool IRQwakeThreads()
 {
     tick++;//Increment tick
+
+    if(sleeping_list.empty()) return false; //If no item in list, return
+    
     bool result=false;
-    for(;;)
+    //Since list is sorted, if we don't need to wake the first element
+    //we don't need to wake the other too
+    for(auto it=sleeping_list.begin();it!=sleeping_list.end();)
     {
-        if(sleeping_list==NULL) break;//If no item in list, return
-        //Since list is sorted, if we don't need to wake the first element
-        //we don't need to wake the other too
-        if(tick != sleeping_list->wakeup_time) break;
-        sleeping_list->p->flags.IRQsetSleep(false);//Wake thread
-        sleeping_list=sleeping_list->next;//Remove from list
+        if(tick<(*it)->wakeupTime) break;
+        //Wake both threads doing absoluteSleep() and timedWait()
+        (*it)->thread->flags.IRQclearSleepAndWait();
+        it=sleeping_list.erase(it);
         result=true;
     }
     return result;
@@ -353,11 +344,12 @@ void Thread::sleep(unsigned int ms)
     //the tick isr will wake threads, modifying the sleeping_list
     {
         FastInterruptDisableLock lock;
-        d.p=const_cast<Thread*>(cur);
-        if(((ms*TICK_FREQ)/1000)>0) d.wakeup_time=getTick()+(ms*TICK_FREQ)/1000;
+        d.thread=const_cast<Thread*>(cur);
+        if(((ms*TICK_FREQ)/1000)>0) d.wakeupTime=getTick()+(ms*TICK_FREQ)/1000;
         //If tick resolution is too low, wait one tick
-        else d.wakeup_time=getTick()+1;
-        IRQaddToSleepingList(&d);//Also sets SLEEP_FLAG
+        else d.wakeupTime=getTick()+1;
+        d.thread->flags.IRQsetSleep(true); //Sleeping thread: set sleep flag
+        IRQaddToSleepingList(&d);
     }
     Thread::yield();
 }
@@ -373,9 +365,10 @@ void Thread::sleepUntil(long long absoluteTime)
     {
         FastInterruptDisableLock lock;
         if(absoluteTime<=getTick()) return; //Wakeup time in the past, return
-        d.p=const_cast<Thread*>(cur);
-        d.wakeup_time=absoluteTime;
-        IRQaddToSleepingList(&d);//Also sets SLEEP_FLAG
+        d.thread=const_cast<Thread*>(cur);
+        d.wakeupTime=absoluteTime;
+        d.thread->flags.IRQsetSleep(true); //Sleeping thread: set sleep flag
+        IRQaddToSleepingList(&d);
     }
     Thread::yield();
 }
@@ -564,6 +557,42 @@ void Thread::IRQwait()
     const_cast<Thread*>(cur)->flags.IRQsetWait(true);
 }
 
+void Thread::PKrestartKernelAndWait(PauseKernelLock& dLock)
+{
+    (void)dLock;
+    //Implemented by upgrading the lock to an interrupt disable one
+    FastInterruptDisableLock dLockIrq;
+    auto savedNesting=kernel_running;
+    kernel_running=0;
+    IRQenableIrqAndWaitImpl();
+    if(kernel_running!=0) errorHandler(UNEXPECTED);
+    kernel_running=savedNesting;
+}
+
+TimedWaitResult Thread::timedWaitMs(long long ms)
+{
+    if (ms <= 0) return TimedWaitResult::Timeout;
+
+    FastInterruptDisableLock dLock;
+    long long ticks = std::max((ms * TICK_FREQ) / 1000, 1LL);
+    long long absoluteTime = getTick() + ticks;
+    return IRQenableIrqAndTimedWaitMsImpl(absoluteTime);
+}
+
+TimedWaitResult Thread::PKrestartKernelAndTimedWaitMs(PauseKernelLock& dLock,
+        long long absoluteTime)
+{
+    (void)dLock;
+    //Implemented by upgrading the lock to an interrupt disable one
+    FastInterruptDisableLock dLockIrq;
+    auto savedNesting=kernel_running;
+    kernel_running=0;
+    auto result=IRQenableIrqAndTimedWaitMsImpl(absoluteTime);
+    if(kernel_running!=0) errorHandler(UNEXPECTED);
+    kernel_running=savedNesting;
+    return result;
+}
+
 void Thread::IRQwakeup()
 {
     this->flags.IRQsetWait(false);
@@ -700,6 +729,37 @@ void Thread::threadLauncher(void *(*threadfunc)(void*), void *argv)
     errorHandler(UNEXPECTED);
 }
 
+void Thread::IRQenableIrqAndWaitImpl()
+{
+    const_cast<Thread*>(cur)->flags.IRQsetWait(true);
+    auto savedNesting=interruptDisableNesting; //For InterruptDisableLock
+    interruptDisableNesting=0;
+    miosix_private::doEnableInterrupts();
+    Thread::yield(); //Here the wait becomes effective
+    miosix_private::doDisableInterrupts();
+    if(interruptDisableNesting!=0) errorHandler(UNEXPECTED);
+    interruptDisableNesting=savedNesting;
+}
+
+TimedWaitResult Thread::IRQenableIrqAndTimedWaitMsImpl(long long absoluteTime)
+{
+    absoluteTime=std::max(absoluteTime,1LL);
+    Thread *t=const_cast<Thread*>(cur);
+    SleepData sleepData(t,absoluteTime);
+    t->flags.IRQsetWait(true); //timedWait thread: set wait flag
+    IRQaddToSleepingList(&sleepData);
+    auto savedNesting=interruptDisableNesting; //For InterruptDisableLock
+    interruptDisableNesting=0;
+    miosix_private::doEnableInterrupts();
+    Thread::yield(); //Here the wait becomes effective
+    miosix_private::doDisableInterrupts();
+    if(interruptDisableNesting!=0) errorHandler(UNEXPECTED);
+    interruptDisableNesting=savedNesting;
+    bool removed=sleeping_list.removeFast(&sleepData);
+    //If the thread was still in the sleeping list, it was woken up by a wakeup()
+    return removed ? TimedWaitResult::NoTimeout : TimedWaitResult::Timeout;
+}
+
 Thread *Thread::allocateIdleThread()
 {
     //NOTE: this function is only called once before the kernel is started, so
@@ -831,6 +891,12 @@ void Thread::ThreadFlags::IRQsetSleep(bool sleeping)
     Scheduler::IRQwaitStatusHook();
 }
 
+void Thread::ThreadFlags::IRQclearSleepAndWait()
+{
+    flags &= ~(WAIT | SLEEP);
+    Scheduler::IRQwaitStatusHook();
+}
+
 void Thread::ThreadFlags::IRQsetDeleted()
 {
     flags |= DELETED;
diff --git a/miosix/kernel/kernel.h b/miosix/kernel/kernel.h
index 9aeb0745..3b58a9c4 100644
--- a/miosix/kernel/kernel.h
+++ b/miosix/kernel/kernel.h
@@ -34,6 +34,7 @@
 #include "interfaces/portability.h"
 #include "kernel/scheduler/sched_types.h"
 #include "stdlib_integration/libstdcpp_integration.h"
+#include "intrusive.h"
 #include <cstdlib>
 #include <new>
 #include <functional>
@@ -388,6 +389,15 @@ bool isKernelRunning();
  */
 long long getTick();
 
+/**
+ * Possible return values of timedWait
+ */
+enum class TimedWaitResult
+{
+    NoTimeout,
+    Timeout
+};
+
 //Forwrd declaration
 struct SleepData;
 class MemoryProfiling;
@@ -580,10 +590,11 @@ public:
     void terminate();
 
     /**
-     * This method stops the thread until another thread calls wakeup() on this
-     * thread.<br>Calls to wait are not cumulative. If wait() is called two
-     * times, only one call to wakeup() is needed to wake the thread.
-     * <br>CANNOT be called when the kernel is paused.
+     * This method stops the thread until wakeup() is called.
+     * Ths method is useful to implement any kind of blocking primitive,
+     * including device drivers.
+     *
+     * CANNOT be called when the kernel is paused.
      */
     static void wait();
 
@@ -595,7 +606,7 @@ public:
 
     /**
      * Wakeup a thread.
-     * <br>Can be called when the kernel is paused.
+     * <br>Can only be called when the kernel is paused.
      */
     void PKwakeup();
 
@@ -644,8 +655,10 @@ public:
     Priority IRQgetPriority();
 
     /**
-     * Same as wait(), but is meant to be used only inside an IRQ or when
-     * interrupts are disabled.<br>
+     * This method stops the thread until wakeup() is called.
+     * Ths method is useful to implement any kind of blocking primitive,
+     * including device drivers.
+     *
      * Note: this method is meant to put the current thread in wait status in a
      * piece of code where interrupts are disbled; it returns immediately, so
      * the user is responsible for re-enabling interrupts and calling yield to
@@ -654,16 +667,164 @@ public:
      * \code
      * disableInterrupts();
      * ...
-     * Thread::IRQwait();//Return immediately
+     * Thread::IRQwait(); //Return immediately
      * enableInterrupts();
-     * Thread::yield();//After this, thread is in wait status
+     * Thread::yield(); //After this, thread is in wait status
      * \endcode
+     *
+     * Consider using IRQenableIrqAndWait() instead.
      */
     static void IRQwait();
 
     /**
-     * Same as wakeup(), but is meant to be used only inside an IRQ or when
-     * interrupts are disabled.
+     * This method stops the thread until wakeup() is called.
+     * Ths method is useful to implement any kind of blocking primitive,
+     * including device drivers.
+     *
+     * NOTE: this method is meant to put the current thread in wait status in a
+     * piece of code where the kernel is paused (preemption disabled).
+     * Preemption will be enabled during the waiting period, and disabled back
+     * before this method returns.
+     *
+     * \param dLock the PauseKernelLock object that was used to disable
+     * preemption in the current context.
+     */
+    static void PKrestartKernelAndWait(PauseKernelLock& dLock);
+
+    /**
+     * This method stops the thread until wakeup() is called.
+     * Ths method is useful to implement any kind of blocking primitive,
+     * including device drivers.
+     *
+     * NOTE: this method is meant to put the current thread in wait status in a
+     * piece of code where interrupts are disbled, interrupts will be enabled
+     * during the waiting period, and disabled back before this method returns.
+     *
+     * \param dLock the InterruptDisableLock object that was used to disable
+     * interrupts in the current context.
+     */
+    static void IRQenableIrqAndWait(InterruptDisableLock& dLock)
+    {
+        (void)dLock; //Common implementation doesn't need it
+        return IRQenableIrqAndWaitImpl();
+    }
+
+    /**
+     * This method stops the thread until wakeup() is called.
+     * Ths method is useful to implement any kind of blocking primitive,
+     * including device drivers.
+     *
+     * NOTE: this method is meant to put the current thread in wait status in a
+     * piece of code where interrupts are disbled, interrupts will be enabled
+     * during the waiting period, and disabled back before this method returns.
+     *
+     * \param dLock the FastInterruptDisableLock object that was used to disable
+     * interrupts in the current context.
+     */
+    static void IRQenableIrqAndWait(FastInterruptDisableLock& dLock)
+    {
+        (void)dLock; //Common implementation doesn't need it
+        return IRQenableIrqAndWaitImpl();
+    }
+
+    /**
+     * This method stops the thread until wakeup() is called or the specified
+     * time in milliseconds has passed.
+     * Ths method is thus a combined IRQwait() and absoluteSleep(), and is
+     * useful to implement any kind of blocking primitive with timeout,
+     * including device drivers.
+     *
+     * \param ms the number of millisecond. If it is <=0 this method will
+     * time out immediately
+     * \return TimedWaitResult::Timeout if the wait timed out
+     */
+    static TimedWaitResult timedWaitMs(long long ms);
+
+    /**
+     * This method stops the thread until wakeup() is called or the specified
+     * absolute time in milliseconds is reached.
+     * Ths method is thus a combined IRQwait() and absoluteSleep(), and is
+     * useful to implement any kind of blocking primitive with timeout,
+     * including device drivers.
+     *
+     * \param absoluteTimeout absolute time after which the wait times out
+     * \return TimedWaitResult::Timeout if the wait timed out
+     */
+    static TimedWaitResult timedWaitUntilMs(long long absoluteTime)
+    {
+        FastInterruptDisableLock dLock;
+        return IRQenableIrqAndTimedWaitMsImpl(absoluteTime);
+    }
+
+    /**
+     * This method stops the thread until wakeup() is called or the specified
+     * absolute time in milliseconds is reached.
+     * Ths method is thus a combined IRQwait() and absoluteSleep(), and is
+     * useful to implement any kind of blocking primitive with timeout,
+     * including device drivers.
+     *
+     * NOTE: this method is meant to put the current thread in wait status in a
+     * piece of code where the kernel is paused (preemption disabled).
+     * Preemption will be enabled during the waiting period, and disabled back
+     * before this method returns.
+     *
+     * \param dLock the PauseKernelLock object that was used to disable
+     * preemption in the current context.
+     * \param absoluteTimeout absolute time after which the wait times out
+     * \return TimedWaitResult::Timeout if the wait timed out
+     */
+    static TimedWaitResult PKrestartKernelAndTimedWaitMs(PauseKernelLock& dLock,
+            long long absoluteTime);
+
+    /**
+     * This method stops the thread until wakeup() is called or the specified
+     * absolute time in milliseconds is reached.
+     * Ths method is thus a combined IRQwait() and absoluteSleep(), and is
+     * useful to implement any kind of blocking primitive with timeout,
+     * including device drivers.
+     *
+     * NOTE: this method is meant to put the current thread in wait status in a
+     * piece of code where interrupts are disbled, interrupts will be enabled
+     * during the waiting period, and disabled back before this method returns.
+     *
+     * \param dLock the InterruptDisableLock object that was used to disable
+     * interrupts in the current context.
+     * \param absoluteTimeout absolute time after which the wait times out
+     * \return TimedWaitResult::Timeout if the wait timed out
+     */
+    static TimedWaitResult IRQenableIrqAndTimedWaitMs(InterruptDisableLock& dLock,
+            long long absoluteTime)
+    {
+        (void)dLock; //Common implementation doesn't need it
+        return IRQenableIrqAndTimedWaitMsImpl(absoluteTime);
+    }
+
+    /**
+     * This method stops the thread until wakeup() is called or the specified
+     * absolute time in milliseconds is reached.
+     * Ths method is thus a combined IRQwait() and absoluteSleep(), and is
+     * useful to implement any kind of blocking primitive with timeout,
+     * including device drivers.
+     *
+     * NOTE: this method is meant to put the current thread in wait status in a
+     * piece of code where interrupts are disbled, interrupts will be enabled
+     * during the waiting period, and disabled back before this method returns.
+     *
+     * \param dLock the FastInterruptDisableLock object that was used to disable
+     * interrupts in the current context.
+     * \param absoluteTimeout absolute time after which the wait times out
+     * \return TimedWaitResult::Timeout if the wait timed out
+     */
+    static TimedWaitResult IRQenableIrqAndTimedWaitMs(FastInterruptDisableLock& dLock,
+            long long absoluteTime)
+    {
+        (void)dLock; //Common implementation doesn't need it
+        return IRQenableIrqAndTimedWaitMsImpl(absoluteTime);
+    }
+
+    /**
+     * Wakeup a thread.
+     * <br>Can only be called inside an IRQ or when interrupts are disabled.
      */
     void IRQwakeup();
 
@@ -755,6 +916,12 @@ private:
          */
         void IRQsetSleep(bool sleeping);
 
+        /**
+         * Used by IRQwakeThreads to clear both the sleep and wait flags,
+         * waking threads doing absoluteSleep() as well as timedWait()
+         */
+        void IRQclearSleepAndWait();
+
         /**
          * Set the deleted flag of the thread. This flag can't be cleared.
          * Can only be called with interrupts disabled or within an interrupt.
@@ -942,7 +1109,17 @@ private:
      * \param argv argument passed to the entry point
      */
     static void threadLauncher(void *(*threadfunc)(void*), void *argv);
-    
+
+    /**
+     * Common implementation of all IRQenableIrqAndWait calls
+     */
+    static void IRQenableIrqAndWaitImpl();
+
+    /**
+     * Common implementation of all timedWait calls
+     */
+    static TimedWaitResult IRQenableIrqAndTimedWaitMsImpl(long long absoluteTime);
+
     /**
      * Allocates the idle thread and makes cur point to it
      * Can only be called before the kernel is started, is called exactly once
@@ -996,8 +1173,6 @@ private:
     //friend functions
     //Needs access to watermark, ctxsave
     friend void miosix_private::IRQstackOverflowCheck();
-    //Need access to status
-    friend void IRQaddToSleepingList(SleepData *x);
     //Needs access to status
     friend bool IRQwakeThreads();
     //Needs access to watermark, status, next
@@ -1052,20 +1227,24 @@ public:
 
 /**
  * \internal
- * \struct Sleep_data
- * This struct is used to make a list of sleeping threads.
+ * This class is used to make a list of sleeping threads.
  * It is used by the kernel, and should not be used by end users.
  */
-struct SleepData
+class SleepData : public IntrusiveListItem
 {
+public:
+    // Default constructor declared for compatibility with the old SleepData class usages
+    SleepData() = default;
+
+    SleepData(Thread *thread, long long wakeupTime)
+        : thread(thread), wakeupTime(wakeupTime) {}
+
     ///\internal Thread that is sleeping
-    Thread *p;
+    Thread *thread;
     
     ///\internal When this number becomes equal to the kernel tick,
     ///the thread will wake
-    long long wakeup_time;
-    
-    SleepData *next;///<\internal Next thread in the list
+    long long wakeupTime;
 };
 
 /**
diff --git a/miosix/kernel/sync.cpp b/miosix/kernel/sync.cpp
index 4f076a74..8489c3f5 100644
--- a/miosix/kernel/sync.cpp
+++ b/miosix/kernel/sync.cpp
@@ -361,60 +361,44 @@ unsigned int Mutex::PKunlockAllDepthLevels(PauseKernelLock& dLock)
 // class ConditionVariable
 //
 
-ConditionVariable::ConditionVariable(): first(0), last(0) {}
-
 void ConditionVariable::wait(Mutex& m)
 {
-    PauseKernelLock dLock;
+    WaitToken listItem(Thread::IRQgetCurrentThread());
     
-    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;
-    }
-    //Unlock mutex and wait
+    PauseKernelLock dLock;
+    unsigned int depth=m.PKunlockAllDepthLevels(dLock);
+    condList.push_back(&listItem);
+
+    // Set the cond wait flag and wait
     {
         FastInterruptDisableLock l;
-        w.p->flags.IRQsetCondWait(true);
+        listItem.thread->flags.IRQsetCondWait(true);
     }
-
-    unsigned int depth=m.PKunlockAllDepthLevels(dLock);
     {
         RestartKernelLock eLock(dLock);
         Thread::yield(); //Here the wait becomes effective
     }
+
+    condList.removeFast(&listItem);
     m.PKlockToDepth(dLock,depth);
 }
 
 void ConditionVariable::wait(FastMutex& m)
 {
+    WaitToken listItem(Thread::IRQgetCurrentThread());
+ 
     FastInterruptDisableLock 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;
-    }
-    //Unlock mutex and wait
-    w.p->flags.IRQsetCondWait(true);
-
     unsigned int depth=IRQdoMutexUnlockAllDepthLevels(m.get());
+    condList.push_back(&listItem);
+
+    // Set the cond wait flag and wait
+    listItem.thread->flags.IRQsetCondWait(true);
     {
         FastInterruptEnableLock eLock(dLock);
         Thread::yield(); //Here the wait becomes effective
     }
+
+    condList.removeFast(&listItem);
     IRQdoMutexLockToDepth(m.get(),dLock,depth);
 }
 
@@ -426,14 +410,14 @@ 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);
         //Check for priority issues
-        if(first->p->IRQgetPriority() >
-                Thread::IRQgetCurrentThread()->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();
@@ -447,15 +431,15 @@ 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);
             //Check for priority issues
-            if(first->p->IRQgetPriority() >
-                Thread::IRQgetCurrentThread()->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 bd6feeae..e142635d 100644
--- a/miosix/kernel/sync.h
+++ b/miosix/kernel/sync.h
@@ -402,7 +402,7 @@ public:
     /**
      * Constructor, initializes the ConditionVariable.
      */
-    ConditionVariable();
+    ConditionVariable() {}
 
     /**
      * Unlock the mutex and wait.
@@ -443,24 +443,23 @@ public:
      */
     void broadcast();
 
-private:
     //Unwanted methods
-    ConditionVariable(const ConditionVariable& );
-    ConditionVariable& operator= (const ConditionVariable& );
+    ConditionVariable(const ConditionVariable& ) = delete;
+    ConditionVariable& operator= (const ConditionVariable& ) = delete;
 
+private:
     /**
-     * \internal
-     * \struct WaitingData
-     * This struct is used to make a list of waiting threads.
+     * \internal Element of a thread waiting list
      */
-    struct WaitingData
+    class WaitToken : public IntrusiveListItem
     {
-        Thread *p;///<\internal Thread that is waiting
-        WaitingData *next;///<\internal Next thread in the list
+    public:
+        WaitToken(Thread *thread) : thread(thread) {}
+        Thread *thread; ///<\internal Waiting thread
     };
 
-    WaitingData *first;///<Pointer to first element of waiting fifo
-    WaitingData *last;///<Pointer to last element of waiting fifo
+    // The list of threads waiting on this condition variable
+    IntrusiveList<WaitToken> condList;
 };
 
 /**
-- 
GitLab