This is a great example of a kind of Polymorphism in C. To borrow terminology from C++, the list_entry()
macro allows you to downcast from a list_head
type to any type that contains it.
Have a look at kthread.c
for a simple fundamental example:
kernel/kthread.c:
struct kthread_create_info
{
/* Information passed to kthread() from kthreadd. */
int (*threadfn)(void *data);
void *data;
int node;
/* Result passed back to kthread_create() from kthreadd. */
struct task_struct *result;
struct completion *done;
struct list_head list;
};
...
int kthreadd(void *unused)
{
...
while (!list_empty(&kthread_create_list)) {
struct kthread_create_info *create;
create = list_entry(kthread_create_list.next,
struct kthread_create_info, list);
...
create_kthread(create);
By including a list_head
object in the kthread_create_info
struct, you can say that kthread_create_info
"derives" from list_head
. This allows kthread_create_info
objects to be used as nodes in a list, meaning you can pass them to any of the functions declared in list.h
by simply dereferencing the list
member of the struct. The list_entry
macro then gives you the mapping from a base class pointer to its derived start address.
In other words, given a list_head
object that you know is contained within an outer kthread_create_info
struct, you can recover a pointer to the kthread_create_info
container.
This is an extremely common pattern in C programming, where object oriented constructs are desired, but a C++ compiler isn't available.