diff --git a/core/clist.c b/core/clist.c deleted file mode 100644 index f5da2f73752e0ef5ed3d06483f34aca9d20b7269..0000000000000000000000000000000000000000 --- a/core/clist.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2013 Freie Universität Berlin - * - * 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. - */ - -/** - * @ingroup core_util - * @{ - * - * @file - * @brief Circular linked list implementation - * - * @author Kaspar Schleiser <kaspar@schleiser.de> - * - * @} - */ - -#include <stddef.h> -#include "clist.h" -#include <stdio.h> - -/* inserts new_node after node */ -void clist_add(clist_node_t **node, clist_node_t *new_node) -{ - if (*node != NULL) { - new_node->next = (*node); - new_node->prev = (*node)->prev; - (*node)->prev->next = new_node; - (*node)->prev = new_node; - - if ((*node)->prev == *node) { - (*node)->prev = new_node; - } - } - else { - *node = new_node; - new_node->next = new_node; - new_node->prev = new_node; - } -} - -/* removes node. */ -void clist_remove(clist_node_t **list, clist_node_t *node) -{ - if (node->next != node) { - node->prev->next = node->next; - node->next->prev = node->prev; - - if (node == *list) { - *list = node->next; - } - } - else { - *list = NULL; - } -} - -#if ENABLE_DEBUG -void clist_print(clist_node_t *clist) -{ - clist_node_t *start = clist, *node = start; - if (!start) { - return; - } - - do { - printf("list entry: %p: prev=%p next=%p\n", - (void *)clist, (void *)clist->prev, (void *)clist->next); - clist = clist->next; - - if (clist == start) { - break; - } - } while (node != start); -} -#endif diff --git a/core/include/clist.h b/core/include/clist.h index 8ab57e034ce742bcda66e8cbc178ad417f53e72f..beda190a5af640166071a4bbd8e2deb5b762f074 100644 --- a/core/include/clist.h +++ b/core/include/clist.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2013 Freie Universität Berlin + * Copyright (C) 2016 Kaspar Schleiser <kaspar@schleiser.de> + * 2013 Freie Universität Berlin * * 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 @@ -13,6 +14,14 @@ * @file * @brief Circular linked list * + * This file contains a circularly linked list implementation. + * + * clist_insert(), clist_remove_head() and clist_advance() take constant time. + * + * Each list is represented as a "clist_node_t". It's only member, the "next" + * pointer, points to the last entry in the list, whose "next" pointer points to + * the first entry. + * * @author Kaspar Schleiser <kaspar@schleiser.de> */ @@ -20,51 +29,67 @@ #define CLIST_H #include "kernel_defines.h" +#include "list.h" #ifdef __cplusplus extern "C" { #endif /** - * @def clist_get_container(NODE, TYPE, MEMBER) - * @brief Returns the container of the circular list - * @details For a struct `TYPE` with a member `MEMBER`, which is a `clist_node_t`, - * given a pointer `NODE` to `TYPE::MEMBER` this function returns a pointer - * to the instance of `TYPE`. - * @details E.g. for `struct my_struct_t { ...; clist_node_t n; ... } my_struct;`, - * `&my_struct == clist_get_container(&my_struct.n, struct my_struct_t, n)`. - * @param[in] NODE pointer to a member - * @param[in] TYPE a type name (a struct or union), container of NODE - * @param[in] MEMBER name of the member of TYPE which NODE points to - * @return Pointer to the container of NODE. - */ -#define clist_get_container(NODE, TYPE, MEMBER) container_of(NODE, TYPE, MEMBER) - -/** - * @brief Structure representing a node in the clist. + * @brief List node structure + * + * Used as is as reference to a list. + * + * clist stores a pointer to the last element of a list. That way, both + * appending to end of list and removing head can be done in constant time. + * + * Actual list objects should have a @c clist_node_t as member and then use + * the container_of() macro in list operations. + * See @ref thread_add_to_list() as example. */ -typedef struct clist_node_t { - struct clist_node_t *next; /**< pointer to next node */ - struct clist_node_t *prev; /**< pointer to the previous node */ -} clist_node_t; +typedef list_node_t clist_node_t; /** - * @brief Inserts *new_node* after *node* into list + * @brief inserts *new_node* into *list* * - * @param[in,out] node Node after which *new_node* gets inserted - * @param[in,out] new_node Node which gets inserted after *node*. + * @param[in,out] list Ptr to clist + * @param[in,out] new_node Node which gets inserted. * Must not be NULL. */ -void clist_add(clist_node_t **node, clist_node_t *new_node); +static inline void clist_insert(clist_node_t *list, clist_node_t *new_node) +{ + if (list->next) { + new_node->next = list->next->next; + list->next->next = new_node; + } + else { + new_node->next = new_node; + } + list->next = new_node; +} /** - * @brief Removes *node* from list + * @brief Removes and returns first element from list * - * @param[in,out] list Pointer to the *list* to remove *node* from. - * @param[in] node Node to remove from *list* - * Must not be NULL. + * @param[in,out] list Pointer to the *list* to remove first element + * from. */ -void clist_remove(clist_node_t **list, clist_node_t *node); +static inline clist_node_t *clist_remove_head(clist_node_t *list) +{ + if (list->next) { + clist_node_t *first = list->next->next; + if (list->next == first) { + list->next = NULL; + } + else { + list->next->next = first->next; + } + return first; + } + else { + return NULL; + } +} /** * @brief Advances the circle list. @@ -75,9 +100,11 @@ void clist_remove(clist_node_t **list, clist_node_t *node); * * @param[in,out] list The list to work upon. */ -static inline void clist_advance(clist_node_t **list) +static inline void clist_advance(clist_node_t *list) { - *list = (*list)->next; + if (list->next) { + list->next = list->next->next; + } } #if ENABLE_DEBUG diff --git a/core/include/sched.h b/core/include/sched.h index b179a636b7e5dc9df13df06383f1567bd5f38a4b..346f4d66823d73d86db2574e9be70b91cc445f25 100644 --- a/core/include/sched.h +++ b/core/include/sched.h @@ -167,7 +167,7 @@ extern volatile kernel_pid_t sched_active_pid; /** * List of runqueues per priority level */ -extern clist_node_t *sched_runqueues[SCHED_PRIO_LEVELS]; +extern clist_node_t sched_runqueues[SCHED_PRIO_LEVELS]; /** * @brief Removes thread from scheduler and set status to #STATUS_STOPPED diff --git a/core/include/thread.h b/core/include/thread.h index 68ca58fedc71289a337cdad21ab1aab8e0222132..fdcb444a055eb5696ab104299b50aa39ed43ce71 100644 --- a/core/include/thread.h +++ b/core/include/thread.h @@ -30,6 +30,7 @@ #include "cpu_conf.h" #include "sched.h" #include "list.h" +#include "clist.h" #ifdef __cplusplus extern "C" { @@ -68,8 +69,8 @@ */ struct _thread { char *sp; /**< thread's stack pointer */ - uint8_t status; /**< thread's status */ - uint8_t priority; /**< thread's priority */ + uint8_t status; /**< thread's status */ + uint8_t priority; /**< thread's priority */ kernel_pid_t pid; /**< thread's process id */ diff --git a/core/mutex.c b/core/mutex.c index f97e088eb8d02ea9e818661213744c56baf0c622..8bfae23d282b01a4a22d854920828113a1a12d09 100644 --- a/core/mutex.c +++ b/core/mutex.c @@ -89,7 +89,7 @@ void mutex_unlock(mutex_t *mutex) return; } - list_node_t *next = (list_node_t*) list_remove_head(&mutex->queue); + list_node_t *next = list_remove_head(&mutex->queue); thread_t *process = container_of((clist_node_t*)next, thread_t, rq_entry); diff --git a/core/sched.c b/core/sched.c index d3fe4e116f795ea303e9b03f5a41b2a0d3dfda2c..151649aad2b300fa3ad13ff2c424a3b9ec9dff1f 100644 --- a/core/sched.c +++ b/core/sched.c @@ -50,7 +50,7 @@ volatile thread_t *sched_active_thread; volatile kernel_pid_t sched_active_pid = KERNEL_PID_UNDEF; -clist_node_t *sched_runqueues[SCHED_PRIO_LEVELS]; +clist_node_t sched_runqueues[SCHED_PRIO_LEVELS]; static uint32_t runqueue_bitcache = 0; #ifdef MODULE_SCHEDSTATISTICS @@ -68,7 +68,7 @@ int sched_run(void) * since the threading should not be started before at least the idle thread was started. */ int nextrq = bitarithm_lsb(runqueue_bitcache); - thread_t *next_thread = clist_get_container(sched_runqueues[nextrq], thread_t, rq_entry); + thread_t *next_thread = container_of(sched_runqueues[nextrq].next->next, thread_t, rq_entry); DEBUG("sched_run: active thread: %" PRIkernel_pid ", next thread: %" PRIkernel_pid "\n", (active_thread == NULL) ? KERNEL_PID_UNDEF : active_thread->pid, @@ -133,7 +133,7 @@ void sched_set_status(thread_t *process, unsigned int status) if (!(process->status >= STATUS_ON_RUNQUEUE)) { DEBUG("sched_set_status: adding thread %" PRIkernel_pid " to runqueue %" PRIu16 ".\n", process->pid, process->priority); - clist_add(&sched_runqueues[process->priority], &(process->rq_entry)); + clist_insert(&sched_runqueues[process->priority], &(process->rq_entry)); runqueue_bitcache |= 1 << process->priority; } } @@ -141,9 +141,9 @@ void sched_set_status(thread_t *process, unsigned int status) if (process->status >= STATUS_ON_RUNQUEUE) { DEBUG("sched_set_status: removing thread %" PRIkernel_pid " to runqueue %" PRIu16 ".\n", process->pid, process->priority); - clist_remove(&sched_runqueues[process->priority], &(process->rq_entry)); + clist_remove_head(&sched_runqueues[process->priority]); - if (!sched_runqueues[process->priority]) { + if (!sched_runqueues[process->priority].next) { runqueue_bitcache &= ~(1 << process->priority); } } diff --git a/core/thread.c b/core/thread.c index a1c1ab56a8a1bfa4541c1745946fe5f3cbcc68f3..1cac0574b7a4f2d4a38b313a739b69d878bfd52a 100644 --- a/core/thread.c +++ b/core/thread.c @@ -224,7 +224,6 @@ kernel_pid_t thread_create(char *stack, int stacksize, char priority, int flags, cb->status = 0; cb->rq_entry.next = NULL; - cb->rq_entry.prev = NULL; cb->wait_data = NULL;