/** * kllist.h is a list implement by linux kernel list * @link https://njusecourse.feishu.cn/wiki/I8vkw2zkwiEInUkujTJc7zzOnwf * @link https://kernelnewlbies.org/FAQ/LinkedLists * @link https://lwn.net/Articles/887097/ * @link https://liuluheng.github.io/wiki/public_html/Embedded-System/kernel/list-and-hlist.html */ #ifndef __KLLIST_H__ #define __KLLIST_H__ #ifndef NULL #define NULL (0) #define __NULL_KLIST_DEFINED__ #endif #ifndef container_of // Magic: https://radek.io/posts/magical-container_of-macro/ // StackOverflow: https://stackoverflow.com/q/15832301/1833118 #ifdef __GNUC__ #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) #else #define container_of(ptr, type, member) ({ \ const void *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) #endif #endif /** * used by list */ struct list_head { struct list_head *next, *prev; }; /** * list init * @example * 1. struct list_head your_list = LIST_HEAD_INIT(your_list); * 2. struct list_head your_list; INIT_LIST_HEAD(&your_list); * 3. LIST_HEAD(your_list); => struct your_list = { &(your_list), &(your_list) }; */ #define LIST_HEAD_INIT(name) { &(name), &(name) } static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) /** * list add */ static inline void __list_add(struct list_head *newl, struct list_head *prev, struct list_head *next) { next->prev = newl; newl->next = next; newl->prev = prev; prev->next = newl; } static inline void list_add(struct list_head *newl, struct list_head *head) { __list_add(newl, head, head->next); } static inline void list_add_tail(struct list_head *newl, struct list_head *head) { __list_add(newl, head->prev, head); } /** * list delete */ static inline void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; } static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); entry->next = NULL; entry->prev = NULL; } /** * list_is_first -- tests whether @list is the first entry in list @head * @list: the entry to test * @head: the head of the list */ static inline int list_is_first(const struct list_head *list, const struct list_head *head) { return list->prev == head; } /** * list_is_last - tests whether @list is the last entry in list @head * @list: the entry to test * @head: the head of the list */ static inline int list_is_last(const struct list_head *list, const struct list_head *head) { return list->next == head; } /** * list_is_head - tests whether @list is the list @head * @list: the entry to test * @head: the head of the list */ static inline int list_is_head(const struct list_head *list, const struct list_head *head) { return list == head; } /** * list_empty - tests whether a list is empty * @head: the list to test. */ static inline int list_empty(const struct list_head *head) { return head->next == head; } /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next) /** * list_for_each_prev - iterate over a list backwards * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; !list_is_head(pos, (head)); pos = pos->prev) /** * list sort * by linux kernel 6.3.1 /lib/list_sort.c * it remain use sigle linked list to merge sort * @link https://www.geeksforgeeks.org/merge-sort-for-linked-list/ */ #ifdef HAVE_KLIST_SORT typedef int (*list_cmp_func_t)(void *, const struct list_head *, const struct list_head *); static void list_sort(void *priv, struct list_head *head, list_cmp_func_t cmp); #endif #if defined(__NULL_KLIST_DEFINED__) && !defined(__NULL_KLIST_DEFINED_NOMOVE__) #undef NULL #endif #endif