一种基于linux内核双向链表的移植

1.简介

 

双向链表(Doubly Linked List)是一种常见的数据结构,由一系列的节点组成,每个节点都包含两个指针,分别指向前一个节点和后一个节点。与单向链表不同,双向链表可以在 O(1) 的时间复杂度内向前或向后遍历、插入或删除节点。

双向链表的节点结构通常由以下几个字段组成:

  • 数据域:存储节点所需的数据。
  • 前驱指针(prev):指向前一个节点。
  • 后继指针(next):指向后一个节点。

双向链表的特点:

  1. 可以双向遍历:通过前驱指针和后继指针,可以从任意一个节点开始,向前或向后遍历整个链表。
  2. 方便插入和删除:相比单向链表,双向链表可以在 O(1) 的时间复杂度内删除或插入一个节点,因为不需要像单向链表那样需要遍历到插入或删除位置的前一个节点。
  3. 占用更多的内存:相比单向链表,双向链表需要额外的空间来存储前驱指针,因此占用的内存更多。

双向链表的应用场景:

  1. 在需要频繁在任意位置插入或删除节点的场景中,双向链表的时间复杂度更优。
  2. 在实现栈、双端队列、LRU Cache 等数据结构时,双向链表可以提供高效的操作。
  3. 在某些算法和技巧中,如快速排序、LRU 缓存策略等,双向链表被广泛应用。

2.linux中的双向链表使用方法

在 Linux 内核中,双向链表是一种常见的数据结构,用于管理和组织数据。下面是 Linux 中双向链表的基本使用方法和说明:

        2.1 定义链表节点结构体:

struct list_head 
{struct list_head *prev;struct list_head *next;
};

每个链表节点包含两个指针,prev 指向前一个节点,next 指向下一个节点。在实际使用中,通常会在自定义的数据结构中嵌入 struct list_head,以便将其作为链表节点使用。

        2.2 初始化链表头:

struct list_head my_list = LIST_HEAD_INIT(my_list);

使用宏 LIST_HEAD_INIT 可以初始化一个链表头,将 prev 和 next 指针设置为指向自身。

        2.3 在链表中插入节点:

struct list_head new_node;
// 初始化新节点
...
// 在链表头部插入节点
list_add(&new_node, &my_list);

使用 list_add 函数可以将一个节点插入到链表的头部。新节点将成为链表的第一个节点,原来的头节点将成为新节点的下一个节点。

        2.4 遍历链表:

struct list_head *pos;
// 从头部开始遍历链表
list_for_each(pos, &my_list) 
{// 访问当前节点struct my_data *data = list_entry(pos, struct my_data, list);// 处理当前节点的数据...
}

使用 list_for_each 宏可以遍历整个链表。在遍历的过程中,可以使用 list_entry 宏将当前节点转换为对应的数据结构类型指针,以便访问节点中存储的数据。

        2.5 从链表中删除节点:

// 从链表中删除指定节点
list_del(&node);

使用 list_del 函数可以从链表中删除指定的节点。

双向链表提供了方便的节点插入、遍历和删除操作。在 Linux 内核中,许多数据结构和算法都使用了双向链表来组织和管理数据。

3.修改一个通用的双向链表

        3.1 下载linux源码

https://www.kernel.org/

        3.2 找到源代码

Linux 内核源代码中的 include/linux/list.h 头文件中找到。

        3.3 修改

以下代码可不依赖如何系统,在单片机,freeRTOS, linux中都可以使用

使用的版本为linux-6.4版本内的双向链表源码修改而来

#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H#include <stdbool.h>
#include <stdio.h>
/** c 双向链表的 基于linux内核版本6.4修改 IOS-C通用* Circular doubly linked list implementation.** Some of the internal functions ("__xxx") are useful when* manipulating whole lists rather than single entries, as* sometimes we already know the next/prev entries and we can* generate better code by using them directly rather than* using the generic single-entry routines.*/struct list_head 
{struct list_head *prev;struct list_head *next;
};struct hlist_head
{struct hlist_node *first;
};struct hlist_node
{struct hlist_node *next, **pprev;
};#ifndef NULL
#define NULL ((void *)0)
#endif#define SAME_TYPE(x, y) (sizeof(x) == sizeof(y))#define LIST_HEAD_INIT(name) { &(name), &(name) }#define LIST_HEAD(name) \struct list_head name = LIST_HEAD_INIT(name)/*** INIT_LIST_HEAD - Initialize a list_head structure* @list: list_head structure to be initialized.** Initializes the list_head to point to itself.  If it is a list header,* the result is an empty list.*/
static inline void INIT_LIST_HEAD(struct list_head *list)
{list->next = list;list->prev = list;
}/** Insert a list_new entry between two known consecutive entries.** This is only for internal list manipulation where we know* the prev/next entries already!*/
static inline void __list_add(struct list_head *list_new, struct list_head *prev,struct list_head *next)
{next->prev = list_new;list_new->next = next;list_new->prev = prev;prev->next = list_new;
}/*** list_add - add a list_new entry* @list_new: list_new entry to be added* @head: list head to add it after** Insert a list_new entry after the specified head.* This is good for implementing stacks.*/
static inline void list_add(struct list_head *list_new, struct list_head *head)
{__list_add(list_new, head, head->next);
}/*** list_add_tail - add a list_new entry* @list_new: list_new entry to be added* @head: list head to add it before** Insert a list_new entry before the specified head.* This is useful for implementing queues.*/
static inline void list_add_tail(struct list_head *list_new, struct list_head *head)
{__list_add(list_new, head->prev, head);
}/** Delete a list entry by making the prev/next entries* point to each other.** This is only for internal list manipulation where we know* the prev/next entries already!*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{next->prev = prev;prev->next = next;
}static inline void __list_del_entry(struct list_head *entry)
{__list_del(entry->prev, entry->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(struct list_head *entry)
{__list_del_entry(entry);
}/*** list_replace - replace old entry by list_new one* @old : the element to be replaced* @list_new : the list_new element to insert** If @old was empty, it will be overwritten.*/
static inline void list_replace(struct list_head *old,struct list_head *list_new)
{list_new->next = old->next;list_new->next->prev = list_new;list_new->prev = old->prev;list_new->prev->next = list_new;
}/*** list_replace_init - replace old entry by list_new one and initialize the old one* @old : the element to be replaced* @list_new : the list_new element to insert** If @old was empty, it will be overwritten.*/
static inline void list_replace_init(struct list_head *old,struct list_head *list_new)
{list_replace(old, list_new);INIT_LIST_HEAD(old);
}/*** list_swap - replace entry1 with entry2 and re-add entry1 at entry2's position* @entry1: the location to place entry2* @entry2: the location to place entry1*/
static inline void list_swap(struct list_head *entry1,struct list_head *entry2)
{struct list_head *pos = entry2->prev;list_del(entry2);list_replace(entry1, entry2);if (pos == entry1)pos = entry2;list_add(entry1, pos);
}/*** list_del_init - deletes entry from list and reinitialize it.* @entry: the element to delete from the list.*/
static inline void list_del_init(struct list_head *entry)
{__list_del(entry->prev, entry->next);INIT_LIST_HEAD(entry);
}/*** list_move - delete from one list and add as another's head* @list: the entry to move* @head: the head that will precede our entry*/
static inline void list_move(struct list_head *list, struct list_head *head)
{__list_del(list->prev, list->next);list_add(list, head);
}/*** list_move_tail - delete from one list and add as another's tail* @list: the entry to move* @head: the head that will follow our entry*/
static inline void list_move_tail(struct list_head *list,struct list_head *head)
{__list_del(list->prev, list->next);list_add_tail(list, head);
}/*** list_bulk_move_tail - move a subsection of a list to its tail* @head: the head that will follow our entry* @first: first entry to move* @last: last entry to move, can be the same as first** Move all entries between @first and including @last before @head.* All three entries must belong to the same linked list.*/
static inline void list_bulk_move_tail(struct list_head *head,struct list_head *first,struct list_head *last)
{first->prev->next = last->next;last->next->prev = first->prev;head->prev->next = first;first->prev = head->prev;last->next = head;head->prev = last;
}/*** 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_empty_careful - tests whether a list is empty and not being modified* @head: the list to test** Description:* tests whether a list is empty _and_ checks that no other CPU might be* in the process of modifying either member (next or prev)** NOTE: using list_empty_careful() without synchronization* can only be safe if the only activity that can happen* to the list entry is list_del_init(). Eg. it cannot be used* if another CPU could re-list_add() it.*/
static inline int list_empty_careful(const struct list_head *head)
{struct list_head *next = head->next;return list_is_head(next, head) && (next == head->prev);
}/*** list_rotate_left - rotate the list to the left* @head: the head of the list*/
static inline void list_rotate_left(struct list_head *head)
{struct list_head *first;if (!list_empty(head)) {first = head->next;list_move_tail(first, head);}
}/*** list_rotate_to_front() - Rotate list to specific item.* @list: The desired list_new front of the list.* @head: The head of the list.** Rotates list so that @list becomes the list_new front of the list.*/
static inline void list_rotate_to_front(struct list_head *list,struct list_head *head)
{/** Deletes the list head from the list denoted by @head and* places it as the tail of @list, this effectively rotates the* list so that @list is at the front.*/list_move_tail(head, list);
}/*** list_is_singular - tests whether a list has just one entry.* @head: the list to test.*/
static inline int list_is_singular(const struct list_head *head)
{return !list_empty(head) && (head->next == head->prev);
}static inline void __list_cut_position(struct list_head *list,struct list_head *head, struct list_head *entry)
{struct list_head *new_first = entry->next;list->next = head->next;list->next->prev = list;list->prev = entry;entry->next = list;head->next = new_first;new_first->prev = head;
}/*** list_cut_position - cut a list into two* @list: a list_new list to add all removed entries* @head: a list with entries* @entry: an entry within head, could be the head itself*	and if so we won't cut the list** This helper moves the initial part of @head, up to and* including @entry, from @head to @list. You should* pass on @entry an element you know is on @head. @list* should be an empty list or a list you do not care about* losing its data.**/
static inline void list_cut_position(struct list_head *list,struct list_head *head, struct list_head *entry)
{if (list_empty(head))return;if (list_is_singular(head) && !list_is_head(entry, head) && (entry != head->next))return;if (list_is_head(entry, head))INIT_LIST_HEAD(list);else__list_cut_position(list, head, entry);
}/*** list_cut_before - cut a list into two, before given entry* @list: a list_new list to add all removed entries* @head: a list with entries* @entry: an entry within head, could be the head itself** This helper moves the initial part of @head, up to but* excluding @entry, from @head to @list.  You should pass* in @entry an element you know is on @head.  @list should* be an empty list or a list you do not care about losing* its data.* If @entry == @head, all entries on @head are moved to* @list.*/
static inline void list_cut_before(struct list_head *list,struct list_head *head,struct list_head *entry)
{if (head->next == entry) {INIT_LIST_HEAD(list);return;}list->next = head->next;list->next->prev = list;list->prev = entry->prev;list->prev->next = list;head->next = entry;entry->prev = head;
}static inline void __list_splice(const struct list_head *list,struct list_head *prev,struct list_head *next)
{struct list_head *first = list->next;struct list_head *last = list->prev;first->prev = prev;prev->next = first;last->next = next;next->prev = last;
}/*** list_splice - join two lists, this is designed for stacks* @list: the list_new list to add.* @head: the place to add it in the first list.*/
static inline void list_splice(const struct list_head *list,struct list_head *head)
{if (!list_empty(list))__list_splice(list, head, head->next);
}/*** list_splice_tail - join two lists, each list being a queue* @list: the list_new list to add.* @head: the place to add it in the first list.*/
static inline void list_splice_tail(struct list_head *list,struct list_head *head)
{if (!list_empty(list))__list_splice(list, head->prev, head);
}/*** list_splice_init - join two lists and reinitialise the emptied list.* @list: the list_new list to add.* @head: the place to add it in the first list.** The list at @list is reinitialised*/
static inline void list_splice_init(struct list_head *list,struct list_head *head)
{if (!list_empty(list)) {__list_splice(list, head, head->next);INIT_LIST_HEAD(list);}
}/*** list_splice_tail_init - join two lists and reinitialise the emptied list* @list: the list_new list to add.* @head: the place to add it in the first list.** Each of the lists is a queue.* The list at @list is reinitialised*/
static inline void list_splice_tail_init(struct list_head *list,struct list_head *head)
{if (!list_empty(list)) {__list_splice(list, head->prev, head);INIT_LIST_HEAD(list);}
}
/*** 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.** WARNING: any const qualifier of @ptr is lost.*/#ifndef container_of
#define container_of(ptr, type, member) \(type *)((char *)ptr - ((size_t) & ((type *)0)->member))
#endif/*** 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_first_entry - get the first element from a list* @ptr:	the list head to take the element from.* @type:	the type of the struct this is embedded in.* @member:	the name of the list_head within the struct.** Note, that list is expected to be not empty.*/
#define list_first_entry(ptr, type, member) \list_entry((ptr)->next, type, member)/*** list_last_entry - get the last element from a list* @ptr:	the list head to take the element from.* @type:	the type of the struct this is embedded in.* @member:	the name of the list_head within the struct.** Note, that list is expected to be not empty.*/
#define list_last_entry(ptr, type, member) \list_entry((ptr)->prev, type, member)/*** list_first_entry_or_null - get the first element from a list* @ptr:	the list head to take the element from.* @type:	the type of the struct this is embedded in.* @member:	the name of the list_head within the struct.** Note that if the list is empty, it returns NULL.*/
#define list_first_entry_or_null(ptr, type, member) ({ \struct list_head *head__ = (ptr); \struct list_head *pos__ = READ_ONCE(head__->next); \pos__ != head__ ? list_entry(pos__, type, member) : NULL; \
})/*** list_next_entry - get the next element in list* @pos:	the type * to cursor* @member:	the name of the list_head within the struct.*/
#define list_next_entry(pos, pos_type, member) \list_entry((pos)->member.next, pos_type, member)/*** list_next_entry_circular - get the next element in list* @pos:	the type * to cursor.* @head:	the list head to take the element from.* @member:	the name of the list_head within the struct.** Wraparound if pos is the last element (return the first element).* Note, that list is expected to be not empty.*/
#define list_next_entry_circular(pos, pos_type, head, member) \(list_is_last(&(pos)->member, head) ? \list_first_entry(head, pos_type, member) : list_next_entry(pos, member))/*** list_prev_entry - get the prev element in list* @pos:	the type * to cursor* @member:	the name of the list_head within the struct.*/
#define list_prev_entry(pos, pos_type, member) \list_entry((pos)->member.prev, pos_type, member)/*** list_prev_entry_circular - get the prev element in list* @pos:	the type * to cursor.* @head:	the list head to take the element from.* @member:	the name of the list_head within the struct.** Wraparound if pos is the first element (return the last element).* Note, that list is expected to be not empty.*/
#define list_prev_entry_circular(pos, pos_type, head, member) \(list_is_first(&(pos)->member, head) ? \list_last_entry(head, pos_type, member) : list_prev_entry(pos, pos_type, member))/*** 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_rcu - Iterate over a list in an RCU-safe fashion* @pos:	the &struct list_head to use as a loop cursor.* @head:	the head for your list.*/
#define list_for_each_rcu(pos, head)		  \for (pos = rcu_dereference((head)->next); \!list_is_head(pos, (head)); \pos = rcu_dereference(pos->next))/*** list_for_each_continue - continue iteration over a list* @pos:	the &struct list_head to use as a loop cursor.* @head:	the head for your list.** Continue to iterate over a list, continuing after the current position.*/
#define list_for_each_continue(pos, head) \for (pos = pos->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_for_each_safe - iterate over a list safe against removal of list entry* @pos:	the &struct list_head to use as a loop cursor.* @n:		another &struct list_head to use as temporary storage* @head:	the head for your list.*/
#define list_for_each_safe(pos, n, head) \for (pos = (head)->next, n = pos->next; \!list_is_head(pos, (head)); \pos = n, n = pos->next)/*** list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry* @pos:	the &struct list_head to use as a loop cursor.* @n:		another &struct list_head to use as temporary storage* @head:	the head for your list.*/
#define list_for_each_prev_safe(pos, n, head) \for (pos = (head)->prev, n = pos->prev; \!list_is_head(pos, (head)); \pos = n, n = pos->prev)/*** list_count_nodes - count nodes in the list* @head:	the head for your list.*/
static inline int list_count_nodes(struct list_head *head)
{struct list_head *pos;int count = 0;list_for_each(pos, head)count++;return count;
}/*** list_entry_is_head - test if the entry points to the head of the list* @pos:	the type * to cursor* @head:	the head for your list.* @member:	the name of the list_head within the struct.*/
#define list_entry_is_head(pos, head, member)				\(&pos->member == (head))/*** list_for_each_entry	-	iterate over list of given type* @pos:	the type * to use as a loop cursor.* @head:	the head for your list.* @member:	the name of the list_head within the struct.*/
#define list_for_each_entry(pos, pos_type, head, member)				\for (pos = list_first_entry(head, pos_type, member);	\!list_entry_is_head(pos, head, member);			\pos = list_next_entry(pos, pos_type, member))/*** list_for_each_entry_reverse - iterate backwards over list of given type.* @pos:	the type * to use as a loop cursor.* @head:	the head for your list.* @member:	the name of the list_head within the struct.*/
#define list_for_each_entry_reverse(pos, pos_type, head, member)			\for (pos = list_last_entry(head, pos_type, member);		\!list_entry_is_head(pos, head, member); 			\pos = list_prev_entry(pos, pos_type, member))/*** list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()* @pos:	the type * to use as a start point* @head:	the head of the list* @member:	the name of the list_head within the struct.** Prepares a pos entry for use as a start point in list_for_each_entry_continue().*/
#define list_prepare_entry(pos, pos_type, head, member) \((pos) ? : list_entry(head, pos_type, member))/*** list_for_each_entry_continue - continue iteration over list of given type* @pos:	the type * to use as a loop cursor.* @head:	the head for your list.* @member:	the name of the list_head within the struct.** Continue to iterate over list of given type, continuing after* the current position.*/
#define list_for_each_entry_continue(pos, head, member) 		\for (pos = list_next_entry(pos, member);			\!list_entry_is_head(pos, head, member);			\pos = list_next_entry(pos, member))/*** list_for_each_entry_continue_reverse - iterate backwards from the given point* @pos:	the type * to use as a loop cursor.* @head:	the head for your list.* @member:	the name of the list_head within the struct.** Start to iterate over list of given type backwards, continuing after* the current position.*/
#define list_for_each_entry_continue_reverse(pos, pos_type, head, member)		\for (pos = list_prev_entry(pos, pos_type, member);			\!list_entry_is_head(pos, head, member);			\pos = list_prev_entry(pos, pos_type, member))/*** list_for_each_entry_from - iterate over list of given type from the current point* @pos:	the type * to use as a loop cursor.* @head:	the head for your list.* @member:	the name of the list_head within the struct.** Iterate over list of given type, continuing from current position.*/
#define list_for_each_entry_from(pos, head, member) 			\for (; !list_entry_is_head(pos, head, member);			\pos = list_next_entry(pos, member))/*** list_for_each_entry_from_reverse - iterate backwards over list of given type*                                    from the current point* @pos:	the type * to use as a loop cursor.* @head:	the head for your list.* @member:	the name of the list_head within the struct.** Iterate backwards over list of given type, continuing from current position.*/
#define list_for_each_entry_from_reverse(pos, pos_type, head, member)		\for (; !list_entry_is_head(pos, head, member);			\pos = list_prev_entry(pos, pos_type, member))/*** list_for_each_entry_safe - iterate over list of given type safe against removal of list entry* @pos:	the type * to use as a loop cursor.* @n:		another type * to use as temporary storage* @head:	the head for your list.* @member:	the name of the list_head within the struct.*/
#define list_for_each_entry_safe(pos, pos_type, n, head, member)			\for (pos = list_first_entry(head, pos_type, member),	\n = list_next_entry(pos, pos_type, member);			\!list_entry_is_head(pos, head, member); 			\pos = n, n = list_next_entry(n, pos_type, member))/*** list_for_each_entry_safe_continue - continue list iteration safe against removal* @pos:	the type * to use as a loop cursor.* @n:		another type * to use as temporary storage* @head:	the head for your list.* @member:	the name of the list_head within the struct.** Iterate over list of given type, continuing after current point,* safe against removal of list entry.*/
#define list_for_each_entry_safe_continue(pos, n, head, member) 		\for (pos = list_next_entry(pos, member), 				\n = list_next_entry(pos, member);				\!list_entry_is_head(pos, head, member);				\pos = n, n = list_next_entry(n, member))/*** list_for_each_entry_safe_from - iterate over list from current point safe against removal* @pos:	the type * to use as a loop cursor.* @n:		another type * to use as temporary storage* @head:	the head for your list.* @member:	the name of the list_head within the struct.** Iterate over list of given type from current point, safe against* removal of list entry.*/
#define list_for_each_entry_safe_from(pos, n, head, member) 			\for (n = list_next_entry(pos, member);					\!list_entry_is_head(pos, head, member);				\pos = n, n = list_next_entry(n, member))/*** list_for_each_entry_safe_reverse - iterate backwards over list safe against removal* @pos:	the type * to use as a loop cursor.* @n:		another type * to use as temporary storage* @head:	the head for your list.* @member:	the name of the list_head within the struct.** Iterate backwards over list of given type, safe against removal* of list entry.*/
#define list_for_each_entry_safe_reverse(pos, pos_type, n, head, member)		\for (pos = list_last_entry(head, pos_type, member),		\n = list_prev_entry(pos, pos_type, member);			\!list_entry_is_head(pos, head, member); 			\pos = n, n = list_prev_entry(n, pos_type, member))/*** list_safe_reset_next - reset a stale list_for_each_entry_safe loop* @pos:	the loop cursor used in the list_for_each_entry_safe loop* @n:		temporary storage used in list_for_each_entry_safe* @member:	the name of the list_head within the struct.** list_safe_reset_next is not safe to use in general if the list may be* modified concurrently (eg. the lock is dropped in the loop body). An* exception to this is if the cursor element (pos) is pinned in the list,* and list_safe_reset_next is called after re-taking the lock and before* completing the current iteration of the loop body.*/
#define list_safe_reset_next(pos, n, member)				\n = list_next_entry(pos, member)/** Double linked lists with a single pointer list head.* Mostly useful for hash tables where the two pointer list head is* too wasteful.* You lose the ability to access the tail in O(1).*/#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
static inline void INIT_HLIST_NODE(struct hlist_node *h)
{h->next = (struct hlist_node *)NULL;h->pprev = (struct hlist_node **)NULL;
}/*** hlist_unhashed - Has node been removed from list and reinitialized?* @h: Node to be checked** Not that not all removal functions will leave a node in unhashed* state.  For example, hlist_nulls_del_init_rcu() does leave the* node in unhashed state, but hlist_nulls_del() does not.*/
static inline int hlist_unhashed(const struct hlist_node *h)
{return !h->pprev;
}/*** hlist_unhashed_lockless - Version of hlist_unhashed for lockless use* @h: Node to be checked** This variant of hlist_unhashed() must be used in lockless contexts* to avoid potential load-tearing.  The READ_ONCE() is paired with the* various WRITE_ONCE() in hlist helpers that are defined below.*/
static inline int hlist_unhashed_lockless(const struct hlist_node *h)
{return !(h->pprev);
}/*** hlist_empty - Is the specified hlist_head structure an empty hlist?* @h: Structure to check.*/
static inline int hlist_empty(const struct hlist_head *h)
{return !(h->first);
}static inline void __hlist_del(struct hlist_node *n)
{struct hlist_node *next = n->next;struct hlist_node **pprev = n->pprev;*pprev = next;if (next)next->pprev = pprev;
}/*** hlist_del - Delete the specified hlist_node from its list* @n: Node to delete.** Note that this function leaves the node in hashed state.  Use* hlist_del_init() or similar instead to unhash @n.*/
static inline void hlist_del(struct hlist_node *n)
{__hlist_del(n);
}/*** hlist_del_init - Delete the specified hlist_node from its list and initialize* @n: Node to delete.** Note that this function leaves the node in unhashed state.*/
static inline void hlist_del_init(struct hlist_node *n)
{if (!hlist_unhashed(n)) {__hlist_del(n);INIT_HLIST_NODE(n);}
}/*** hlist_add_head - add a list_new entry at the beginning of the hlist* @n: list_new entry to be added* @h: hlist head to add it after** Insert a list_new entry after the specified head.* This is good for implementing stacks.*/
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{struct hlist_node *first = h->first;n->next = first;if (first)first->pprev = &n->next;h->first = n;n->pprev = &h->first;
}/*** hlist_add_before - add a list_new entry before the one specified* @n: list_new entry to be added* @next: hlist node to add it before, which must be non-NULL*/
static inline void hlist_add_before(struct hlist_node *n,struct hlist_node *next)
{n->pprev = next->pprev;n->next = next;next->pprev = &n->next;*(n->pprev) = n;
}/*** hlist_add_behind - add a list_new entry after the one specified* @n: list_new entry to be added* @prev: hlist node to add it after, which must be non-NULL*/
static inline void hlist_add_behind(struct hlist_node *n,struct hlist_node *prev)
{n->next = prev->next;prev->next =  n;n->pprev = &prev->next;if (n->next)n->next->pprev = &n->next;
}/*** hlist_add_fake - create a fake hlist consisting of a single headless node* @n: Node to make a fake list out of** This makes @n appear to be its own predecessor on a headless hlist.* The point of this is to allow things like hlist_del() to work correctly* in cases where there is no list.*/
static inline void hlist_add_fake(struct hlist_node *n)
{n->pprev = &n->next;
}/*** hlist_fake: Is this node a fake hlist?* @h: Node to check for being a self-referential fake hlist.*/
static inline bool hlist_fake(struct hlist_node *h)
{return h->pprev == &h->next;
}/*** hlist_is_singular_node - is node the only element of the specified hlist?* @n: Node to check for singularity.* @h: Header for potentially singular list.** Check whether the node is the only node of the head without* accessing head, thus avoiding unnecessary cache misses.*/
static inline bool
hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h)
{return !n->next && n->pprev == &h->first;
}/*** hlist_move_list - Move an hlist* @old: hlist_head for old list.* @list_new: hlist_head for list_new list.** Move a list from one list head to another. Fixup the pprev* reference of the first entry if it exists.*/
static inline void hlist_move_list(struct hlist_head *old,struct hlist_head *list_new)
{list_new->first = old->first;if (list_new->first)list_new->first->pprev = &list_new->first;old->first = (struct hlist_node *)NULL;
}#define hlist_entry(ptr, type, member) container_of(ptr,type,member)#define hlist_for_each(pos, head) \for (pos = (head)->first; pos ; pos = pos->next)#define hlist_for_each_safe(pos, n, head) \for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \pos = n)#define hlist_entry_safe(ptr, ptr_type, type, member) \({ ptr_type ____ptr = (ptr); \____ptr ? hlist_entry(____ptr, type, member) : NULL; \})/*** hlist_for_each_entry	- iterate over list of given type* @pos:	the type * to use as a loop cursor.* @head:	the head for your list.* @member:	the name of the hlist_node within the struct.*/
#define hlist_for_each_entry(pos, pos_type, head, member)				\for (pos = hlist_entry_safe((head)->first, pos_type, member);\pos;							\pos = hlist_entry_safe((pos)->member.next, pos_type, member))/*** hlist_for_each_entry_continue - iterate over a hlist continuing after current point* @pos:	the type * to use as a loop cursor.* @member:	the name of the hlist_node within the struct.*/
#define hlist_for_each_entry_continue(pos, pos_type, member)			\for (pos = hlist_entry_safe((pos)->member.next, pos_type, member);\pos;							\pos = hlist_entry_safe((pos)->member.next, pos_type, member))/*** hlist_for_each_entry_from - iterate over a hlist continuing from current point* @pos:	the type * to use as a loop cursor.* @member:	the name of the hlist_node within the struct.*/
#define hlist_for_each_entry_from(pos, pos_type, member)				\for (; pos;							\pos = hlist_entry_safe((pos)->member.next, pos_type, member))/*** hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry* @pos:	the type * to use as a loop cursor.* @n:		a &struct hlist_node to use as temporary storage* @head:	the head for your list.* @member:	the name of the hlist_node within the struct.*/
#define hlist_for_each_entry_safe(pos, pos_type, n, head, member) 		\for (pos = hlist_entry_safe((head)->first, pos_type, member);\pos && ({ n = pos->member.next; 1; });			\pos = hlist_entry_safe(n, pos_type, member))#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/1472.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

虚拟机VMware+Ubuntu配置DPDK环境并运行Helloworld

虚拟机VMwareUbuntu配置DPDK环境并运行Helloworld 文章目录 虚拟机VMwareUbuntu配置DPDK环境并运行Helloworld安装虚拟机虚拟机中安装DPDK运行Helloworld 首先需要强调的是&#xff0c;版本的影响很大&#xff0c;有可能会因为版本不匹配而导致无法成功配置DPDK环境。 安装虚拟…

火山引擎 Iceberg 数据湖的应用与实践

在云原生计算时代&#xff0c;云存储使得海量数据能以低成本进行存储&#xff0c;但是这也给如何访问、管理和使用这些云上的数据提出了挑战。而 Iceberg 作为一种云原生的表格式&#xff0c;可以很好地应对这些挑战。本文将介绍火山引擎在云原生计算产品上使用 Iceberg 的实践…

Scrapy框架之认识MongoDB

目录 MongoDB 简介 特点 MongoDB的适用场景 MongoDB的行业具体应用 如何抉择是否使用MongoDB MongoDB 简介 MongoDB 是免费开源的跨平台 NoSQL 数据库&#xff0c;命名源于英文单词 humongous&#xff0c;意思是「巨大无比」&#xff0c;可见开发组对 MongoDB 的定位。…

函数模板和类模板 知识点总结 C++程序设计与算法笔记总结(七) 北京大学 郭炜

函数模板 交换两个整型变量的值的Swap函数&#xff1a; void Swap(int & x,int & y) { int tmp x; x y; y tmp; } 交换两个double型变量的值的Swap函数: void Swap(double & x,double & y) { double tmp x; x y; y tmp; }用函数模板解决&#xff1a; …

计算几何——gitf-wrapping算法

几何中的"gift-wrapping"算法&#xff0c;又称为"Jarvis算法"&#xff0c;是一种用于计算凸包(convex hull)的方法。下面我将为你解释一下该算法的步骤&#xff1a; 1. 找到具有最小x坐标的点P&#xff0c;我们将其作为凸包的起点。 2. 将P标记为当前点&a…

Java Spring概述

1、Spring是什么&#xff1f; Spring 是一款主流的 Java EE 轻量级开源框架 &#xff0c;Spring 由“Spring 之父”Rod Johnson 提出并创立&#xff0c;其目的是用于简化 Java 企业级应用的开发难度和开发周期。Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦…

MySQL 备份与恢复

MySQL 备份与恢复 一、数据库备份的分类1.1 数据备份的重要性1.2 数据库备份的分类1.2.1 从物理与逻辑的角度&#xff0c;分为物理备份和逻辑备份1.2.2 从数据库的备份策略角度&#xff0c;分为完全备份&#xff0c;差异备份和增量备份1.2.3 常见的备份方法 二、MySQL完全备份与…

GreenPlum版本升级

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

10个图像处理的Python库

在这篇文章中&#xff0c;我们将整理计算机视觉项目中常用的Python库&#xff0c;如果你想进入计算机视觉领域&#xff0c;可以先了解下本文介绍的库&#xff0c;这会对你的工作很有帮助。 1、PIL/Pillow Pillow是一个通用且用户友好的Python库&#xff0c;提供了丰富的函数集…

芯片等高科技制造业 如何实现安全的跨网数据交换?

芯片是信息产业的基础&#xff0c;一直以来占据全球半导体产品超过80%的销售额&#xff0c;在计算机、家用电器、数码电子、自动化、电气、通信、交通、医疗、航空航天等几乎所有的电子设备领域中都有使用。 所以&#xff0c;对于芯片这种高科技制造业来说&#xff0c;数据的安…

新项目搞完啦!!!

大家好&#xff0c;我是鱼皮。 经过了 7 场直播&#xff0c;总时长近 20 小时&#xff0c;我在 自己的编程导航 的第 5 个 全程直播开发 的项目 —— 智能 BI 项目&#xff0c;完结啦&#xff01; 我在这里对该项目做一个简单的总结&#xff0c;希望让更多需要它的同学看到&am…

开发框架前后端分离的好处是什么

关于将前端和后端保持在一起或分开&#xff0c;存在广泛的意见分歧。唯一重要的是&#xff0c;这两个组件对于开发成熟的应用程序都是必需的。 考虑&#xff1a;紧密耦合的前端和后端 许多人认为后端和前端的分离是一个坏主意&#xff0c;这两个角色之间没有太大区别。 以下…