Kernel has a good implementation of double linked lists and objectives in this post are to emphasize how can you do the following list operations:
- Defining/Declaring and Initializing
- Passing through
- Addition and deletion of elements
The linked list API is located in include/linux/list.h and the basic MACROs and functions that you need to know about are:
-
INIT_LIST_HEAD()
-
list_add(), list_entry(), and list_del()
- list_for_each() and list_for_each_safe()
The first thing you should do when you want to use a linked list, is to declare and declare your list node data type. In this case the node is different than any linked list node that you may know outside the kernel.
Therefore a double linked list node would seem like:
struct person { char name[64]; // .. struct person *next; struct person *prev; };
but in the kernel way would be as:
struct person { char *name; // .. struct list_head engineers; struct list_head managers; // we can have multiple lists! };
How do we define a linked list?
Simple:
struct person employees;
Pushing forward towards our objectives, examples of code are:
Initializing:
INIT_LIST_HEAD(&employees.engineers);
Element addition:
struct person *node = NULL; node=(struct person *)vmalloc(sizeof(person)); if (!node){ printk(KERN_INFO "mymodule:vmalloc: could not alocate memory"); return -ENOMEM; } memset(node, 0, sizeof(person)); strcpy(node->name, person_name); list_add(&(node->engineers),&(employees.engineers));
Passing through list and deleting an element:
struct list_head *pos = NULL; struct list_head *q = NULL; struct person *node = NULL; list_for_each_safe(pos, q, &employees.engineers) { node=list_entry(pos, struct person, engineers); if (!strcmp(node->name, person_name)) { list_del(pos); vfree(node); } }
I hope I haven’t forgotten, or misplaced anything during code translation.