// SPDX-License-Identifier: GPL-2.0 /* This code was taken by looking at list header definition in the linux kernel source file /include/linux/list.h. The code was modified accordingly to get a usable user-space version. Date: 2020-12-08. */ #ifndef NULL #define NULL 0 #endif // ------------------------- // Data structure // ------------------------- struct list_head { struct list_head *next, *prev; }; // ------------------------- // List Initialization // ------------------------- static inline void INIT_LIST_HEAD(struct list_head *list) { // In the kernel this is a WRITE_ONCE() operation list->next = list; list->prev = list; }; // ------------------------- // List Insertion // ------------------------- static inline int __list_add_valid(struct list_head *new_node, struct list_head *prev, struct list_head *next) { // In the kernel this function always returns true unless the value // CONFIG_DEBUG_LIST is defined. return 1; } static inline void __list_add(struct list_head *new_node, struct list_head *prev, struct list_head *next) { if (!__list_add_valid(new_node, prev, next)) return; next->prev = new_node; new_node->next = next; new_node->prev = prev; // In the kernel this is a WRITE_ONCE() operation prev->next = new_node; } /** * list_add - add a new entry * @new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */ static inline void list_add(struct list_head *new_node, struct list_head *head) { __list_add(new_node, head, head->next); } /** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static inline void list_add_tail(struct list_head *new_node, struct list_head *head) { __list_add(new_node, head->prev, head); } // ------------------------- // List Deletion // ------------------------- static inline int __list_del_entry_valid(struct list_head *entry) { // In the kernel this function always returns true unless the value // CONFIG_DEBUG_LIST is defined. return 1; } static inline void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; // In the kernel this is a WRITE_ONCE() operation prev->next = next; } /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty() on entry does not return true after this, the entry is * in an undefined state. */ static inline void __list_del_entry(struct list_head *entry) { if (!__list_del_entry_valid(entry)) return; __list_del(entry->prev, entry->next); } static inline void list_del(struct list_head *entry) { __list_del_entry(entry); // In the kernel LIST_POISON1 is used instead of NULL entry->next = NULL; // In the kernel LIST_POISON2 is used instead of NULL entry->prev = NULL; } // ------------------------- // List entry macro // ------------------------- // In the kernel code the container_of there is a check with // BUILD_BUG_ON_MSG() checking if the pointer type missmatch. /** * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. * */ #define container_of(ptr, type, member) ({ \ void *__mptr = (void *)(ptr); \ ((type *)(__mptr - __builtin_offsetof(type, member))); }) /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_head within the struct. */ #define list_entry(ptr, type, member) container_of(ptr, type, member) // ------------------------- // List Iteration // ------------------------- /** * 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; pos != (head); pos = pos->next)