I have just passed the hlist-related functions and macro definitions, and I have done some work here. I hope it will be useful for you to learn about Linux in the future.
/* The Linux linked list designer (think that double-ended double-chain tables (next, Prev) are "too wasteful" for hash tables ", therefore, we have designed a set of hlist data structures for hash table applications-a single-finger-header dual-loop linked list. The hlist header has only one pointer to the first node, but not to the end node, in this way, the header stored in a massive hash table can reduce the space consumption by half.
*/
// Hash list
// Header node (different from the data structure of the node)
struct hlist_head { struct hlist_node *first;};
/* Pprev is also a pointer first, but it is a pointer to the pointer (please be careful ), in hlist, pprev points to the next address of the previous variable in the current hlist_node variable,
If it is the first element, this value points to the first address. If it is the last node, it points to null. If you have a better understanding,
In fact, the * pprev and next variables respectively indicate the pointer to your own and the pointer to other nodes.
*/
Struct hlist_node {// node struct hlist_node * Next, ** pprev ;};
// Initialize the struct hlist_head variable.
#define HLIST_HEAD_INIT { .first = NULL }
// Define a struct hlist_head node and initialize it as null
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
// Initialize the struct hlist_head node.
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
// This macro function initializes a variable of the struct hlist_node node. This macro is used in operations on the node after the node is deleted.
#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL)
/* H: struct hlist_node node pointer.
Judge whether H-> Prev is null. If the direction of pprev is null, this node is not added to the linked list. If it is null, true is returned. Otherwise, false */is returned */
static inline int hlist_unhashed(const struct hlist_node *h){ return !h->pprev;}
/* H: struct hlist_head node pointer (the header node of the hlist linked list ).
Determines whether the hlist linked list is empty. If yes, true is returned. Otherwise, false is returned.
*/
static inline int hlist_empty(const struct hlist_head *h){ return !h->first;}
/* Functions that actually implement the delete operation.
N: The node to be deleted.
For the delete operation, check whether N is the end node. If n is the end node, next is null. Therefore, no pprev pointing to can be modified, otherwise, modify it.
*/
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;}
/* N: the node to be deleted.
In this function, N nodes are deleted first, and then two pointers of N nodes are directed to list_posion, indicating that N nodes are unavailable.
*/
static inline void hlist_del(struct hlist_node *n){ __hlist_del(n); n->next = LIST_POISON1; n->pprev = LIST_POISON2;}
/* N: the node to be deleted.
First, check whether the pprev to be deleted is empty. If yes, you cannot delete it. Otherwise, delete the pprev. After the deletion is complete, point the next and pprev values of N nodes to null (initialize nodes ).
*/
static inline void hlist_del(struct hlist_node *n){ __hlist_del(n); n->next = LIST_POISON1; n->pprev = LIST_POISON2;}
/*
N: The new node to be added.
H: The header node of the hlist linked list.
This function adds a new hlist_node node to the next and first nodes of H, similar to header insertion.
*/
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;}
/* Next must be! = NULL */
/*
N: The new node to be added.
Next: add n before the next node.
Add a new node n before the next node. Note that next cannot be null when using this function.
*/
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;}
/* N: add next after N nodes.
Next: The new node to be added.
Add a new node next after N nodes. N cannot be null.
*/
static inline void hlist_add_after(struct hlist_node *n, struct hlist_node *next){ next->next = n->next; n->next = next; next->pprev = &n->next; if(next->next) next->next->pprev = &next->next;}
/* Note: The macro definition in hlist is similar to the macro definition in list. Therefore, this is a simple analysis. For details, refer to the above Code */
/* PTR: an address of the struct hlist_node type.
Type: struct name
Member: name of the hlist_node member variable in the type struct
This macro has been analyzed in the list linked list to get the first address of the struct of the address pointed by PTR.
*/
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
/* Pos: A pointer of the struct hlist_node type;
Head: A pointer of the struct hlist_head type, indicating the head node of the hlist linked list.
In fact, this is a for loop, with a traversal chain from start to end.
*/
#define hlist_for_each(pos, head) \ for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ pos = pos->next)
/* In fact, this is a for loop, covering the chain tables from start to end. This is different from the previous one by adding N, which is used to prevent chain breaking during traversal.
POs: A pointer of the struct hlist_node type;
N: A pointer of the struct hlist_node type;
Head: A pointer of the struct hlist_head type, indicating the head node of the hlist linked list.
*/
#define hlist_for_each_safe(pos, n, head) \ for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ pos = n)
/* Tops: The address used to store the retrieved data structure. The type is type *;
POs: A pointer of the struct hlist_node type;
Head: The head node of the hlist linked list;
Member: the name of the variable in the type struct of struct hlist_node.
In the loop, we can use tops to point to any variable of the type struct.
*/
#define hlist_for_each_entry(tpos, pos, head, member) \ for (pos = (head)->first; \ pos && ({ prefetch(pos->next); 1;}) && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next)
/* Tops: The address used to store the retrieved data structure. The type is type *;
POs: A pointer of the struct hlist_node type;
Member: the name of the variable in the type struct of struct hlist_node.
This macro starts to traverse from the next element of the POs address.
*/
#define hlist_for_each_entry_continue(tpos, pos, member) \ for (pos = (pos)->next; \ pos && ({ prefetch(pos->next); 1;}) && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next)
/* Tops: The address used to store the retrieved data structure. The type is type *;
POs: A pointer of the struct hlist_node type;
Member: the name of the variable in the type struct of struct hlist_node.
This macro starts to traverse from the POs address.
*/
#define hlist_for_each_entry_from(tpos, pos, member) \ for (; pos && ({ prefetch(pos->next); 1;}) && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next)
/* Tops: The address used to store the retrieved data structure. The type is type *;
POs: A pointer of the struct hlist_node type;
N: A pointer of the struct hlist_node type;
Head: The head node of the hlist linked list;
Member: the name of the variable in the type struct of struct hlist_node.
In the loop, we can use tops to point to any variable of the type struct. This macro function is introduced to prevent deleting nodes during traversal.
*/
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ for (pos = (head)->first; \ pos && ({ n = pos->next; 1; }) && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = n)#endif