关于Linux内核list.h中list_entry宏注释含义及使用示例的问询
list_entry and Its Comment "get the struct for this entry" Let's break this down clearly—first the comment's meaning, then how this macro works with a concrete example.
What Does "get the struct for this entry" Mean?
In Linux kernel linked lists, we don’t structure lists like traditional implementations (where the data is wrapped inside a node with next/prev pointers). Instead, we embed a struct list_head directly inside our custom data struct.
The phrase "get the struct for this entry" translates to:
When you hold a pointer to a
struct list_headinstance (the "entry" referenced in the comment), this macro gives you a pointer to the full custom struct that contains thislist_headentry.
Think of it as reverse-engineering: you have a small piece of the struct (the linked list node), and you want to get back to the complete parent struct it belongs to.
How list_entry Works
Under the hood, list_entry is just a wrapper for the container_of macro. It calculates the starting address of the parent struct using three inputs:
ptr: The address of the embeddedlist_headentrytype: The data type of the parent structmember: The name of thelist_headmember inside the parent struct
The logic is straightforward: it subtracts the memory offset of the list_head member from the member's address to get the start of the parent struct. The formula looks like this:
parent_struct_ptr = (type *)((char *)ptr - offsetof(type, member))
Practical Example
Let’s build a kernel-style example to see this in action.
Step 1: Define a Custom Struct with Embedded list_head
#include <linux/list.h> #include <linux/slab.h> #include <linux/printk.h> // Our custom data struct, with a list_head to link into a list struct process_info { pid_t pid; char cmd[64]; struct list_head link; // This is the "entry" we'll reference later };
Step 2: Initialize the List and Add Entries
// Static list head to anchor our linked list static LIST_HEAD(process_list); // Helper function to create and add a process_info entry to the list struct process_info *add_process(pid_t pid, const char *cmd) { struct process_info *proc = kmalloc(sizeof(*proc), GFP_KERNEL); if (!proc) return NULL; proc->pid = pid; strscpy(proc->cmd, cmd, sizeof(proc->cmd)); INIT_LIST_HEAD(&proc->link); // Initialize the embedded list_head // Add the new entry to the end of the list list_add_tail(&proc->link, &process_list); return proc; }
Step 3: Use list_entry to Retrieve the Parent Struct
When traversing the list, we get pointers to struct list_head instances. We use list_entry to map these back to the full struct process_info:
// Traverse the list and print process details void print_processes(void) { // Option 1: Use the helper macro list_for_each_entry (uses list_entry internally) struct process_info *proc; list_for_each_entry(proc, &process_list, link) { pr_info("Process: PID=%d, Cmd=%s\n", proc->pid, proc->cmd); } // Option 2: Manual use of list_entry (for clarity) struct list_head *current_link; list_for_each(current_link, &process_list) { // current_link is a pointer to &proc->link; use list_entry to get proc struct process_info *current_proc = list_entry(current_link, struct process_info, link); pr_info("Manual: PID=%d, Cmd=%s\n", current_proc->pid, current_proc->cmd); } }
In both cases, list_entry takes the current_link (the "entry" from the comment) and gives us the full struct process_info that contains it.
Key Takeaway
The comment "get the struct for this entry" is simply stating: given a pointer to the embedded list_head node (the entry), this macro retrieves the pointer to the parent struct that this node is part of. This is the foundation of Linux kernel linked lists—since list nodes are embedded in custom structs, we always need this reverse lookup to access the actual data we care about.
内容的提问来源于stack exchange,提问作者user15874403

