Kernel Primitives/Linked List
From Linux Drivers
Contents |
Basic APIs
Defining a list
#include <linux/list.h> struct my_list_struct { struct list_head list; };
Initializing a list
If the linked list is a global variable.
LIST_HEAD(my_list);
Otherwise
INIT_LIST_HEAD(my_list);
Adding an entry
After allocating an object,
struct my_list_struct *pobj = kmalloc(sizeof(struct my_list_struct), GFP_KERNEL);
to insert the new object into the beginning of the list,
list_add(&pobj->list, &my_list);
or to add the object to the tail of the list
list_add_tail(&pobj->list, &my_list);
Deleting an entry
To remove an entry out of the list,
list_del(&pobj->list);
Testing
To test whether the list is empty
if (list_empty(&my_list)) printk("list is empty.\n");
To test whether an entry is the last entry in the list,
if (list_is_last(pobj, &my_list)) printk("last entry.\n");
Traversing
To find the first entry in the list.
struct my_list_struct *pobj = list_first_entry(&my_list, struct my_list_struct, list);
To traverse the list from head to tail.
struct list_head *entry; struct my_list_struct *pobj; list_for_each(entry, &my_list) { pobj = list_entry(entry, struct my_list_struct, list); .... }
or
struct my_list_struct *pobj; list_for_each_entry(pobj, &my_list, list) { .... }
If entries can be deleted while traversing a list, there are other set of APIs.
struct list_head *entry, *tmp; struct my_list_struct *pobj; list_for_each_safe(entry, tmp, &my_list) { pobj = list_entry(entry, struct my_list_struct, list); list_del(&pobj->list); kfree(pobj); }
or,
struct my_list_struct *pobj, *tmp; list_for_each_entry_safe(pobj, tmp, &my_list, list) { list_del(&pobj->list); kfree(pobj); }
To traverse the list in reverse order.
- list_for_each => list_for_each_prev
- list_for_each_entry => list_for_each_entry_reverse
- list_for_each_safe => list_for_each_prev_safe
- list_for_each_entry_safe => list_for_each_entry_safe_reverse