Classic macro definitions in Linux Offsetof
Definition: Offsetof is defined in the include/linux/stddef.h of the Linux kernel.
#define OFFSETOF (Type, MEMBER) ((size_t) & ((TYPE *) 0)->member)
description : Gets the offset of the variable member (MEMBER) of the struct body (TYPE) in this struct.
() ((TYPE *) 0) transforms 0 to type pointer, that is, the address of the type pointer is 0.
(->member) ((TYPE *) 0) accesses data members in the structure.
& (((TYPE *) 0)->member The address of the data member. Because the address of type is 0, the address obtained here is the offset of the relative member in type.
(size_t) (& ((type*) 0)->member) The type of the result conversion. For 32-bit systems, size_t is the unsigned int type, and for 64-bit systems, size_t is the unsigned long type.
Container_of
definition : container_of is defined in the include/linux/kernel.h of the Linux kernel.
#define CONTAINER_OF (PTR, type, member) ({ const typeof (((type *) 0)->member) *__mptr = (PTR); (Type *) ((char *) __mptr-offsetof (Type,member));})
description : Gets a pointer to the entire struct variable, based on the pointer (PTR) of the domain member variable (member) in the struct (type) variable.
typeof (((type *) 0)->member) takes out the variable type of the member member.
Const typeof (((type *) 0)->member) *__mptr = (PTR) defines the variable __mptr pointer and assigns PTR to __mptr. After this step, __mptr is a constant pointer to the member data type, which points to the address that PTR points to.
(__mptr) (char *) converts the __mptr to a byte-type pointer.
Offsetof (Type,member)) is to get the position offset of the member member in struct type.
(char *) __mptr-offsetof (Type,member)) is the starting address of a pointer to the struct type (a char * type pointer).
(s) (Type *) ((char *) __mptr-offsetof (Type,member)) is a pointer to the struct type of type "char *" to the "type *" of the structure of types.
Linux bidirectional linked list implementation
The definition of a Linux doubly linked list is mainly related to two files:
Include/linux/types.h
Include/linux/list.h
(01). Node definition
struct List_head { struct list_head *next, *prev;};
Although the name is List_head, it is both a table header for a doubly linked list and a node for a doubly linked list.
(02). Initializing nodes
#define LIST_HEAD_INIT (name) {& (name), & (name)}
#define LIST_HEAD (name) \
struct List_head name = List_head_init (name)
static inline void Init_list_head (struct list_head *list)
{
List->next = list;
List->prev = list;
}
The role of List_head is to define the header (node): Create a new doubly linked list header name, and set the name of the forward and subsequent nodes to point to name itself.
The function of List_head_init is to initialize the node: the first and subsequent nodes of the name node are set to the name itself.
Init_list_head, like List_head_init, is the initialization node: the forward and subsequent nodes of the list node point to the list itself.
(03). Adding nodes
Static inline void __list_add (struct list_head *new,
& nbsp; struct List_head *prev,
struct List_head *next)
{
Next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
static inline void List_add (struct list_head *new, struct list_head *head)
{
__li St_add (New, head, Head->next);
}
static inline void List_add_tail (struct list_head *new, struct list_head *head)
{
; __list_add (New, Head->prev, head);
}
The role of __list_add (new, Prev, next) is to add nodes: Insert new between Prev and next. In Linux, a function that begins with "__" means the internal interface of the kernel, which should not be invoked externally.
The role of List_add (new, head) is to add a new node: After adding new to the head, it is the successor of new called Head.
The role of List_add_tail (new, head) is to add the new node: Before adding new to the head, add new to the end of the doubly linked list.
(04). Deleting nodes
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);
}
static inline void __list_del_entry (struct list_head *entry)
{
__list_del (Entry->prev, Entry->next);
}
static inline void List_del_init (struct list_head *entry)
{
__list_del_entry (entry);
Init_list_head (entry);
}
__list_del (prev, next) and __list_del_entry (entry) are the internal interfaces of the Linux kernel.
The role of __list_del (prev, next) is to remove the node between Prev and next from the doubly linked list.
The role of __list_del_entry (entry) is to remove entry nodes from the doubly linked list.
List_del (Entry) and List_del_init (entry) are external interfaces to the Linux kernel.
The role of List_del (entry) is to remove entry nodes from the doubly linked list.
The role of List_del_init (entry) is to remove the entry node from the doubly linked list and point the entry node's predecessor and successor nodes to the entry itself.
(05). Replace Node
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;}
The role of List_replace (old, new) is to replace the old node with the new node.
(06). Determine if the double-linked list is empty
static inline int list_empty (const struct List_head *head)
{
return head->next = = head;
}
The role of the List_empty (head) is to determine whether the doubly linked list is empty. It is judged by distinguishing "the successor of the table header" from the "table header itself".
(07). Get node
#define List_entry (PTR, type, member) container_of (PTR, type, member)
List_entry (PTR, type, member) is actually the CONTAINER_OF macro that is called.
Its purpose is to obtain a pointer to the entire struct variable, based on the pointer (PTR) of the domain member variable (member) in the struct (type) variable.
(08). Traversing nodes
#define List_for_each (POS, head) for (pos = (head)->next; pos! = (head); pos = pos->next) #define List_for_each_s AFE (POS, N, head) for (pos = (head)->next, n = pos->next; pos! = (head); pos = N, n = pos->next)
The role of List_for_each (POS, head) and List_for_each_safe (POS, N, head) is to traverse the linked list. But their use is different!
List_for_each (POS, head) is typically used to get nodes, but not to delete a node's scene.
List_for_each_safe (POS, N, head) typically deletes a node's scene.