From 7c39134d5d3bab79274ea3affbef62202c54d570 Mon Sep 17 00:00:00 2001
From: Kaspar Schleiser <kaspar@schleiser.de>
Date: Sat, 17 Jan 2015 15:17:19 +0100
Subject: [PATCH] core: introduce intrusive singly linked list

---
 core/include/list.h   | 77 +++++++++++++++++++++++++++++++++++++++++++
 core/include/thread.h | 16 +++++++++
 core/thread.c         | 20 +++++++++++
 3 files changed, 113 insertions(+)
 create mode 100644 core/include/list.h

diff --git a/core/include/list.h b/core/include/list.h
new file mode 100644
index 0000000000..375827696a
--- /dev/null
+++ b/core/include/list.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+ /**
+ * @addtogroup  core_util
+ * @{
+ *
+ * @file
+ * @brief       Intrusive linked list
+ *
+ * Lists are represented as element pointing to the first actual list element.
+ *
+ * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ */
+
+#ifndef LIST_H
+#define LIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief List node structure
+ *
+ * Used as is as reference to a list, or as member of any data structure that
+ * should be member of a list.
+ *
+ * Actual list objects should have a @c list_node_t as member and then use
+ * the container_of() macro in list operations.
+ * See @ref thread_add_to_list() as example.
+ */
+typedef struct list_node {
+    struct list_node *next;     /**< pointer to next list entry */
+} list_node_t;
+
+/**
+ * @brief Insert object into list
+ *
+ * If called with a list reference as node, the new node will become the new
+ * list head.
+ *
+ * @param[in] node      list node before new entry
+ * @param[in] new_node  list node to insert
+ */
+static inline void list_add(list_node_t *node, list_node_t *new_node) {
+    new_node->next = node->next;
+    node->next = new_node;
+}
+
+/**
+ * @brief Removes the head of the list and returns it
+ *
+ * @param[in] list  Pointer to the list itself, where list->next points
+ *                  to the root node
+ *
+ * @return  removed old list head, or NULL if empty
+ */
+static inline list_node_t* list_remove_head(list_node_t *list) {
+    list_node_t* head = list->next;
+    if (head) {
+        list->next = head->next;
+    }
+    return head;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIST_H */
+/** @} */
diff --git a/core/include/thread.h b/core/include/thread.h
index cec1b7bcdb..68ca58fedc 100644
--- a/core/include/thread.h
+++ b/core/include/thread.h
@@ -29,6 +29,7 @@
 #include "arch/thread_arch.h"
 #include "cpu_conf.h"
 #include "sched.h"
+#include "list.h"
 
 #ifdef __cplusplus
  extern "C" {
@@ -315,6 +316,21 @@ char *thread_stack_init(thread_task_func_t task_func, void *arg, void *stack_sta
  */
 void thread_print_msg_queue(void);
 
+/**
+ * @brief Add thread to list, sorted by priority (internal)
+ *
+ * This will add @p thread to @p list sorted by the thread priority.
+ * It reuses the thread's rq_entry field.
+ * Used internally by msg and mutex implementations.
+ *
+ * @note Only use for threads *not on any runqueue* and with interrupts
+ *       disabled.
+ *
+ * @param[in] list      ptr to list root node
+ * @param[in] thread    thread to add
+ */
+void thread_add_to_list(list_node_t *list, thread_t *thread);
+
 #ifdef DEVELHELP
 /**
  * @brief Returns the name of a process
diff --git a/core/thread.c b/core/thread.c
index 4fadbf3014..a1c1ab56a8 100644
--- a/core/thread.c
+++ b/core/thread.c
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <stdio.h>
 
+#include "assert.h"
 #include "thread.h"
 #include "irq.h"
 
@@ -104,6 +105,25 @@ void thread_yield(void)
     thread_yield_higher();
 }
 
+void thread_add_to_list(list_node_t *list, thread_t *thread)
+{
+    assert (thread->status < STATUS_ON_RUNQUEUE);
+
+    uint16_t my_prio = thread->priority;
+    list_node_t *new_node = (list_node_t*)&thread->rq_entry;
+
+    while (list->next) {
+        thread_t *list_entry = container_of((clist_node_t*)list->next, thread_t, rq_entry);
+        if (list_entry->priority > my_prio) {
+            break;
+        }
+        list = list->next;
+    }
+
+    new_node->next = list->next;
+    list->next = new_node;
+}
+
 #ifdef DEVELHELP
 uintptr_t thread_measure_stack_free(char *stack)
 {
-- 
GitLab