Linux内核链表(list)移植到任意平台
一、前言
linux内核链表在include/linux/list.h文件中,内核中实现的链表比较简洁,实用性很强,因此想把它单独移植出来使用。
内核中的代码只能使用gnuc编译器编译,stdc编译器编译是会报错的,主要是因为typeof这个宏是gnuc特有的扩展,stdc中没有此扩展。
本篇文章就是来解决这个问题的,移植得到一个在stdc下运行的list,方便其他平台使用。
二、移植过程
-
1、将
include/linux/list.h单独扣出来,保存为list.h文件。 -
2、修改头文件,并添加
list_head的定义,还有部分宏定义,以下为添加部分:#include <stdbool.h> #include <stddef.h>struct list_head {struct list_head *next, *prev; };struct hlist_head {struct hlist_node *first; };struct hlist_node {struct hlist_node *next, **pprev; };#define WRITE_ONCE(var, val) ((var) = (val)) #define READ_ONCE(var) (var)/* container_of */ #ifndef offsetof #define offsetof(type, member) (size_t)(&((type*)0)->member) #endif #define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))修改并添加了以下宏,改完后可以在stdc下编译:
- 1、
WRITE_ONCE和READ_ONCE。 - 2、
container_of,去除了typeof的使用。
- 1、
-
3、删除所有使用
typeof的定义,将以下所有使用到typeof的代码删除:
/*** 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, member) \list_entry((pos)->member.next, typeof(*(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, member) \list_entry((pos)->member.prev, typeof(*(pos)), member)/*** 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, head, member) \for (pos = list_first_entry(head, typeof(*pos), member); \&pos->member != (head); \pos = list_next_entry(pos, 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, head, member) \for (pos = list_last_entry(head, typeof(*pos), member); \&pos->member != (head); \pos = list_prev_entry(pos, 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, head, member) \((pos) ? : list_entry(head, typeof(*pos), 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, n, head, member) \for (pos = list_first_entry(head, typeof(*pos), member), \n = list_next_entry(pos, member); \&pos->member != (head); \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, n, head, member) \for (pos = list_last_entry(head, typeof(*pos), member), \n = list_prev_entry(pos, member); \&pos->member != (head); \pos = n, n = list_prev_entry(n, member))#define hlist_entry_safe(ptr, type, member) \({ typeof(ptr) ____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, head, member) \for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\pos; \pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), 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, member) \for (pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member);\pos; \pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), 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, member) \for (; pos; \pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), 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: another &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, n, head, member) \for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\pos && ({ n = pos->member.next; 1; }); \pos = hlist_entry_safe(n, typeof(*pos), member))
至此,移植完成。
三、移植好的list.h文件
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H#include <stdbool.h>
#include <stddef.h>struct list_head {struct list_head *next, *prev;
};struct hlist_head {struct hlist_node *first;
};struct hlist_node {struct hlist_node *next, **pprev;
};#define WRITE_ONCE(var, val) ((var) = (val))
#define READ_ONCE(var) (var)/* container_of */
#ifndef offsetof
#define offsetof(type, member) (size_t)(&((type*)0)->member)
#endif
#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))/** 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.*/#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)
{WRITE_ONCE(list->next, list);list->prev = list;
}static inline bool __list_add_valid(struct list_head *new,struct list_head *prev,struct list_head *next)
{return true;
}
static inline bool __list_del_entry_valid(struct list_head *entry)
{return true;
}/** Insert a 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 *new,struct list_head *prev,struct list_head *next)
{if (!__list_add_valid(new, prev, next))return;next->prev = new;new->next = next;new->prev = prev;WRITE_ONCE(prev->next, new);
}/*** 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, struct list_head *head)
{__list_add(new, 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, struct list_head *head)
{__list_add(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;WRITE_ONCE(prev->next, next);
}/** Delete a list entry and clear the 'prev' pointer.** This is a special-purpose list clearing method used in the networking code* for lists allocated as per-cpu, where we don't want to incur the extra* WRITE_ONCE() overhead of a regular list_del_init(). The code that uses this* needs to check the node 'prev' pointer instead of calling list_empty().*/
static inline void __list_del_clearprev(struct list_head *entry)
{__list_del(entry->prev, entry->next);entry->prev = NULL;
}static inline void __list_del_entry(struct list_head *entry)
{if (!__list_del_entry_valid(entry))return;__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);entry->next = NULL;entry->prev = NULL;
}/*** list_replace - replace old entry by new one* @old : the element to be replaced* @new : the new element to insert** If @old was empty, it will be overwritten.*/
static inline void list_replace(struct list_head *old,struct list_head *new)
{new->next = old->next;new->next->prev = new;new->prev = old->prev;new->prev->next = new;
}/*** list_replace_init - replace old entry by new one and initialize the old one* @old : the element to be replaced* @new : the 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 *new)
{list_replace(old, 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(entry);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_entry(list);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_entry(list);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 READ_ONCE(head->next) == head;
}/*** list_del_init_careful - deletes entry from list and reinitialize it.* @entry: the element to delete from the list.** This is the same as list_del_init(), except designed to be used* together with list_empty_careful() in a way to guarantee ordering* of other memory operations.** Any memory operations done before a list_del_init_careful() are* guaranteed to be visible after a list_empty_careful() test.*/
static inline void list_del_init_careful(struct list_head *entry)
{__list_del_entry(entry);entry->prev = entry;WRITE_ONCE(entry->next, entry);
}/*** 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 = READ_ONCE(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 new front of the list.* @head: The head of the list.** Rotates list so that @list becomes the 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 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 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 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 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 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 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);}
}/*** 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_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_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_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_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, head, member) \for (pos = list_prev_entry(pos, member); \!list_entry_is_head(pos, head, member); \pos = list_prev_entry(pos, 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, head, member) \for (; !list_entry_is_head(pos, head, member); \pos = list_prev_entry(pos, 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_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 = NULL;h->pprev = 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 !READ_ONCE(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 !READ_ONCE(h->first);
}static inline void __hlist_del(struct hlist_node *n)
{struct hlist_node *next = n->next;struct hlist_node **pprev = n->pprev;WRITE_ONCE(*pprev, next);if (next)WRITE_ONCE(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);n->next = NULL;n->pprev = NULL;
}/*** 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 new entry at the beginning of the hlist* @n: new entry to be added* @h: hlist head to add it after** Insert a 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;WRITE_ONCE(n->next, first);if (first)WRITE_ONCE(first->pprev, &n->next);WRITE_ONCE(h->first, n);WRITE_ONCE(n->pprev, &h->first);
}/*** hlist_add_before - add a new entry before the one specified* @n: 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)
{WRITE_ONCE(n->pprev, next->pprev);WRITE_ONCE(n->next, next);WRITE_ONCE(next->pprev, &n->next);WRITE_ONCE(*(n->pprev), n);
}/*** hlist_add_behind - add a new entry after the one specified* @n: 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)
{WRITE_ONCE(n->next, prev->next);WRITE_ONCE(prev->next, n);WRITE_ONCE(n->pprev, &prev->next);if (n->next)WRITE_ONCE(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.* @new: hlist_head for 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 *new)
{new->first = old->first;if (new->first)new->first->pprev = &new->first;old->first = 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)#endif
四、使用方法
- 4.1、初始化链表
struct mailbox_data {u8 chan;u32 cmd;u32 data;int (*func)(struct mailbox_data *mailbox);struct list_head head;
};LIST_HEAD(mailbox_list_head);
或
struct mailbox_data {u8 chan;u32 cmd;u32 data;int (*func)(struct mailbox_data *mailbox);struct list_head head;
};struct mailbox_head mailbox_list_head;
INIT_LIST_HEAD(&mailbox_list_head);
- 4.2、添加链表
struct mailbox_data* mailbox = calloc(1, sizeof(*mailbox));
list_add_tail(&mailbox->head, &mailbox_list_head);
- 4.3、遍历链表
struct list_head* pos = NULL;
struct list_head* pt = NULL;
struct mailbox_data* mailbox = NULL;list_for_each_safe(pos, pt, &mailbox_list_head) {mailbox = list_entry(pos, struct mailbox_data, head);if (mailbox->func) {mailbox->func(mailbox);}list_del(&mailbox ->head);free(mailbox);
}
- 4.4、删除链表
list_del(&mailbox ->head);
相关文章:
Linux内核链表(list)移植到任意平台
一、前言 linux内核链表在include/linux/list.h文件中,内核中实现的链表比较简洁,实用性很强,因此想把它单独移植出来使用。 内核中的代码只能使用gnuc编译器编译,stdc编译器编译是会报错的,主要是因为typeof这个宏是…...
【操作系统】聊聊什么是CPU上下文切换
对于linux来说,本身就是一个多任务运行的操作系统,运行远大于CPU核心数的程序,从用户视角来看是并发执行,而在CPU视角看其实是将不同的CPU时间片进行分割,每个程序执行一下,就切换到别的程序执行。那么这个…...
CMake教程-第 2 步 添加一个库
CMake教程-第 2 步 添加一个库 1 CMake教程介绍2 学习步骤Step 1: A Basic Starting PointStep 2: Adding a LibraryStep 3: Adding Usage Requirements for a LibraryStep 4: Adding Generator ExpressionsStep 5: Installing and TestingStep 6: Adding Support for a Testin…...
DS 顺序表--类实现(C++数据结构题)
实现顺序表的用 C 语言和类实现顺序表 属性包括:数组、实际长度、最大长度(设定为 1000 ) 操作包括:创建、插入、删除、查找 类定义参考 #include<iostream> using namespace std; #define ok 0 #define error -1 // 顺…...
0.UML
1.图 1.1类图含义 第一层显示类的名称,如果是抽象类,则就用斜体显示。第二层是类的特性,通常就是字段和属性。第三层是类的操作,通常是方法或行为。注意前面的符号, ,表示public,-,表示private,#,表示protected。 1.2接口图 与类图的区别主要是顶端有<< interface >…...
PostgreSQL设置主键为自增
1、创建自增序列 CREATE SEQUENCE table_name_id_seq START 1; 2、设置字段默认值 字段默认值中设置 nextval(table_name_id_seq) 3、常用查询 -- 查询所有序列 select * from information_schema.sequences where sequence_schema public; -- 查询自增序列的当前值 select cu…...
input修改checkbox复选框默认选中样式
问题描述: <input type"checkbox" /> input修改checkbox默认选中样式,直接设置选中后的样式不生效,需要先给复选框设置-webkit-appearance: none(取消默认样式), 再设置样式才会生效。 …...
高云FPGA系列教程(10):letter-shell移植
文章目录 letter-shell简介letter-shell源码获取letter-shell移植函数和变量应用示例 本文是高云FPGA系列教程的第10篇文章。 shell,中文是外壳的意思,就是操作系统的外壳。通过shell命令可以操作和控制操作系统,比如Linux中的Shell命令就包括…...
【C语言学习笔记---指针进阶02】
C语言程序设计笔记---017 C语言进阶之回调函数1、函数指针数组2、回调函数3、 回调函数的应用 --- qsort库函数4、模拟qsort函数5、结语 C语言进阶之回调函数 前言: 通过C语言进阶前篇的指针进阶01的知识,继续学习。这篇引用一个简易计算器的程序进行深…...
低功耗蓝牙物联网:未来连接的无限可能
物联网是连接各种设备和传感器的网络,其目的是实现信息的交换和共享,提高效率并优化生活。在这个领域,低功耗蓝牙(BLE)正在发挥着越来越重要的作用。 低功耗蓝牙是一种无线通信技术,它的主要特点是低功耗和…...
安装社区版本OB
获取一键安装包 https://www.oceanbase.com/softwarecenter 离线安装 [admintest001 ~]$ tar -xzf oceanbase-all-in-one-*.tar.gz [admintest001 ~]$ cd oceanbase-all-in-one/bin/ [admintest001 bin]$ ./install.sh [admintest001 bin]$ source ~/.oceanbase-all-in-one/…...
JSON 串和 Java 对象的相互转换
JSON 串和 Java 对象的相互转换 以 json 格式的数据进行前后端交互 前端发送请求时,如果是复杂的数据就会以 json 提交给后端; 而后端如果需要响应一些复杂的数据时,也需要以 json 格式将数据响应回给浏览器 为达到以上目的就需要重点学习…...
爬虫 — App 爬虫(一)
目录 一、介绍二、APP 爬虫常见反爬三、APP 抓包常用工具四、模拟器五、安装 APP1、下载 APP2、安装 APP 六、fiddler1、工作原理2、安装3、基本介绍 七、环境配置1、fiddler 的配置2、夜神模拟器的配置 八、案例 一、介绍 爬虫分类——数据来源 1、PC 端爬虫(网页…...
如何使用正则表达式实现Java日志信息的抓取与收集
首先,什么是Java日志信息?简单来说,Java应用程序在运行过程中会输出一些信息,这些信息可以用来追踪程序运行状态、调试错误等。而Java日志信息就是这些输出信息的集合。 那么为什么要抓取和收集Java日志信息呢?一方面…...
C/C++算法入门 | 简单模拟
不爱生姜不吃醋⭐️ 如果本文有什么错误的话欢迎在评论区中指正 与其明天开始,不如现在行动! 文章目录 🌴前言🌴一、害死人不偿命的(3n1)猜想1.题目(PAT B1001)2.思路3.代码实现 &am…...
stm32学习-芯片系列/选型/开发方式
【03】STM32HAL库开发-初识STM32 | STM概念、芯片分类、命名规则、选型 | STM32原理图设计、看数据手册、最小系统的组成 、STM32IO分配_小浪宝宝的博客-CSDN博客 STM32:ST是意法半导体,M是MCU/MPU,32是32位。 ST累计推出了:…...
mnist数据集
训练模型 import tensorflow as tfimport keras from keras.models import Sequential from keras.layers import Dense,Dropout, Flatten,Conv2D, MaxPooling2D # from keras.optimizers import SGD from tensorflow.keras.optimizers import Adam,Nadam, SGDfrom PIL import…...
Java之IO概述以及
1.1 什么是IO 生活中,你肯定经历过这样的场景。当你编辑一个文本文件,忘记了ctrls ,可能文件就白白编辑了。当你电脑上插入一个U盘,可以把一个视频,拷贝到你的电脑硬盘里。那么数据都是在哪些设备上的呢?键…...
Spring WebFlux—Reactive 核心
一、概述 spring-web 模块包含以下对响应式Web应用的基础支持: 对于服务器请求处理,有两个级别的支持。 HttpHandler: 用于HTTP请求处理的基本约定,具有非阻塞I/O和Reactive Streams背压,以及Reactor Netty、Undertow、Tomcat、…...
由于找不到d3dx9_43.dll,无法继续执行代码要怎么解决
D3DX9_43.dll是一个动态链接库文件,它是DirectX的一个组件,主要用于支持一些旧版本的游戏和软件。当电脑缺少这个文件时,可能会导致这些游戏和软件无法正常运行。例如,一些老游戏可能需要D3DX9_43.dll来支持图形渲染等功能。此外&…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...
R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
