From c66b05216d911923aeda4ce3561fa08196b3f31f Mon Sep 17 00:00:00 2001 From: fef Date: Sun, 24 Oct 2021 21:55:54 +0200 Subject: [PATCH] clist: add better debugging facilities --- cmake/config.cmake | 4 +++- include/gay/clist.h | 21 +++++++++++++++++ include/gay/config.h.in | 3 +++ include/gay/util.h | 16 ++++--------- kernel/clist.c | 51 ++++++++++++++++++++++++++++++++++++++--- 5 files changed, 80 insertions(+), 15 deletions(-) diff --git a/cmake/config.cmake b/cmake/config.cmake index fbba136..5bbcc95 100644 --- a/cmake/config.cmake +++ b/cmake/config.cmake @@ -14,7 +14,9 @@ option(CFG_POISON_PAGES "Poison pages after allocate and free" ON) option(CFG_POISON_HEAP "Poison heap memory after kmalloc() and kfree()" ON) -option(CFG_DEBUG_IRQ "Debug IRQs" ON) +option(CFG_DEBUG_IRQ "Debug IRQs" ${DEBUG}) + +option(CFG_DEBUG_CLIST "Sanitize clist operations" ${DEBUG}) option(CFG_DEBUG_PAGE_ALLOCS "Debug page frame allocations" OFF) diff --git a/include/gay/clist.h b/include/gay/clist.h index 57cb5c7..fc26ae1 100644 --- a/include/gay/clist.h +++ b/include/gay/clist.h @@ -7,6 +7,7 @@ #pragma once +#include #include /** @@ -62,6 +63,26 @@ void clist_add_first(struct clist *head, struct clist *new); */ void clist_del(struct clist *node); +/** + * @brief Remove and return the first node in a clist. + * If the list is empty and `CFG_DEBUG_CLIST` is defined, this returns nil. + * If `CFG_DEBUG_CLIST` is not defined in this case, it will blow up. + * + * @param head Head of the list + * @return The deleted node + */ +struct clist *clist_del_first(struct clist *head); + +/** + * @brief Remove and return the last node in a clist. + * If the list is empty and `CFG_DEBUG_CLIST` is defined, this returns nil. + * If `CFG_DEBUG_CLIST` is not defined in this case, it will blow up. + * + * @param head Head of the list + * @return The deleted node + */ +struct clist *clist_del_last(struct clist *head); + /** * @brief Return whether a clist is empty. * diff --git a/include/gay/config.h.in b/include/gay/config.h.in index 822789c..4efd91b 100644 --- a/include/gay/config.h.in +++ b/include/gay/config.h.in @@ -34,6 +34,9 @@ /** @brief Debug IRQs */ #cmakedefine01 CFG_DEBUG_IRQ +/** @brief Sanitize clist operations */ +#cmakedefine01 CFG_DEBUG_CLIST + /** @brief Debug page frame allocations */ #cmakedefine01 CFG_DEBUG_PAGE_ALLOCS diff --git a/include/gay/util.h b/include/gay/util.h index 99e534b..98f1078 100644 --- a/include/gay/util.h +++ b/include/gay/util.h @@ -41,17 +41,11 @@ #define container_of(ptr, type, member) \ ((type *)( (void *)(ptr) - offsetof(type, member) )) -/** - * @brief Do an evil raw cast. - * - * @param type Type to cast to - * @param expr Expression to cast - * @returns The raw value of `expr`, cast to `type` - */ -#define raw_cast(type, expr) ({ \ - typeof(expr) __expr = (expr); \ - *(type *)&__expr; \ -}) +/** @brief Determine whether `ptr` is kinda sus. */ +static __always_inline bool sus_nil(const void *ptr) +{ + return ptr < (void *)0x1000; +} /** * @brief Align `ptr` such that `ptr % n == 0`. diff --git a/kernel/clist.c b/kernel/clist.c index 19353b8..45f7cf8 100644 --- a/kernel/clist.c +++ b/kernel/clist.c @@ -2,15 +2,32 @@ #include #include +#include void clist_init(struct clist *head) { +# if CFG_DEBUG_CLIST + if (head->next == head && head->prev == head) + kprintf("clist_init(%p) called multiple times\n", head); +# endif + head->next = head; head->prev = head; } void clist_add(struct clist *head, struct clist *new) { +# if CFG_DEBUG_CLIST + if (sus_nil(head->next) || sus_nil(head->prev)) { + kprintf("clist_add(%p, %p): head seems uninitialized\n", head, new); + return; + } + if (sus_nil(new)) { + kprintf("clist_add(%p, %p): new node is NULL!\n", head, new); + return; + } +# endif + head->prev->next = new; new->next = head; @@ -32,10 +49,38 @@ void clist_del(struct clist *node) node->next->prev = node->prev; node->prev->next = node->next; -# ifdef DEBUG - node->next = NULL; - node->prev = NULL; +# if CFG_DEBUG_CLIST + node->next = nil; + node->prev = nil; +# endif +} + +struct clist *clist_del_first(struct clist *head) +{ +# if CFG_DEBUG_CLIST + if (clist_is_empty(head)) { + kprintf("clist_del_first(%p): empty list!\n", head); + return nil; + } # endif + + struct clist *first = head->next; + clist_del(first); + return first; +} + +struct clist *clist_del_last(struct clist *head) +{ +# ifdef CFG_DEBUG_CLIST + if (clist_is_empty(head)) { + kprintf("clist_del_last(%p): empty list!\n", head); + return nil; + } +# endif + + struct clist *last = head->prev; + clist_del(last); + return last; } /*