Linked List : list_is_last
In this program, you are going to learn
How to test whether a list is the last entry in list ?
How to use the below API’s ?
In this example, we are going to test whether a list is the first entry in list.
Add the list of header files to refer the APIs used in this program.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/slab.h>
Add the modules macro which lists the information about the license, author and description.
MODULE_LICENSE("GPL");
MODULE_AUTHOR("linux_usr");
MODULE_DESCRIPTION("Linked List");
list_head
is used to initialize the list.
static struct list_head my_list;
INIT_LIST_HEAD
is used to initialize a list_head structure.
INIT_LIST_HEAD(&my_list);
INIT_LIST_HEAD(&new_node->list);
Add the module init function to execute the function once when the module is loaded to the linux kernel.
static int __init linkedlist_init(void)
{
struct list_node *entry;
pr_info("Driver loaded\n");
INIT_LIST_HEAD(&my_list);
insert_func(2);
display();
last_entry = list_last_entry(&my_list, struct list_node, list);
pr_info("The last entry has value : %d\n", last_entry->data);
if (list_is_last(&last_entry->list, &my_list))
pr_info("The first entry is the last entry!\n");
return 0;
}
list_last_entry
will give the last entry of the list.
last_entry = list_last_entry(&my_list, struct list_node, list);
list_is_last
tests whether a list is the last entry in list.
list_is_last(&last_entry->list, &my_list);
Add module exit function which is executed once the module is unloaded from the kernel.
static void __exit linkedlist_exit(void)
{
struct list_node *ptr, *next;
list_for_each_entry_safe(ptr, next, &my_list, list) {
list_del(&ptr->list);
kfree(ptr);
}
pr_info("Driver unloaded\n");
}
insert_rear
function inserts a new node at the end with the givenvalue
into the linked list.
void insert_rear(int value)
{
struct list_node * new_node;
new_node = kmalloc(sizeof(struct list_node), GFP_KERNEL);
if (!new_node) {
pr_err("Memory allocation failed\n");
return;
}
new_node->data = value;
INIT_LIST_HEAD(&new_node->list);
list_add_tail(&new_node->list, &my_list);
}
display
function iterates through the linked list usinglist_for_each_entry
. It prints the data in each node to the kernel log.
void display(void)
{
struct list_node * ptr;
pr_info("Linked list: ");
list_for_each_entry(ptr, &my_list, list) {
printk(KERN_CONT "%d -> ", ptr->data);
}
printk(KERN_CONT "NULL\n");
}
Add the module init and exit which is called when the module is loaded and unloaded.
module_init(linkedlist_init);
module_exit(linkedlist_exit);
1#include <linux/init.h>
2#include <linux/module.h>
3#include <linux/kernel.h>
4#include <linux/list.h>
5#include <linux/slab.h>
6
7MODULE_LICENSE("GPL");
8MODULE_AUTHOR("linux_usr");
9MODULE_DESCRIPTION("Linked List");
10
11struct list_node {
12 int data;
13 struct list_head list;
14};
15
16static struct list_head my_list;
17
18void insert_func(int value)
19{
20 struct list_node *new_node;
21
22 new_node = kmalloc(sizeof(struct list_node), GFP_KERNEL);
23
24 if (!new_node) {
25 pr_err("Memory allocation failed\n");
26 return;
27 }
28
29 new_node->data = value;
30 INIT_LIST_HEAD(&new_node->list);
31 list_add_tail(&new_node->list, &my_list);
32}
33
34void display(void)
35{
36 struct list_node *ptr;
37
38 pr_info("Linked list: ");
39 list_for_each_entry(ptr, &my_list, list) {
40 printk(KERN_CONT "%d -> ", ptr->data);
41 }
42
43 printk(KERN_CONT "NULL\n");
44}
45
46
47static int __init linkedlist_init(void)
48{
49 struct list_node *last_entry;
50
51 pr_info("Driver loaded\n");
52
53 INIT_LIST_HEAD(&my_list);
54
55 insert_func(2);
56
57 display();
58
59 last_entry = list_last_entry(&my_list, struct list_node, list);
60 pr_info("The last entry has value : %d\n", last_entry->data);
61
62 if (list_is_last(&last_entry->list, &my_list))
63 pr_info("The first entry is the last entry!\n");
64
65 return 0;
66}
67
68static void __exit linkedlist_exit(void)
69{
70 struct list_node *ptr, *next;
71
72 list_for_each_entry_safe(ptr, next, &my_list, list) {
73 list_del(&ptr->list);
74 kfree(ptr);
75 }
76
77 pr_info("Driver unloaded\n");
78}
79
80module_init(linkedlist_init);
81module_exit(linkedlist_exit);
1obj-m += linked_list.o
2all:
3 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
4clean:
5 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Run Make to compile the module.
$make
make -C /lib/modules/5.4.0-150-generic/build M=$HOME/kernel_linked_list modules
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-150-generic'
CC [M] $HOME/kernel_linked_list/linked_list.o
Building modules, stage 2.
MODPOST 1 modules
CC [M] $HOME/kernel_linked_list/linked_list.mod.o
LD [M] $HOME/kernel_linked_list/linked_list.ko
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-150-generic'
Run ls to check if linked_list.ko is generated or not.
$ ls -l
total 36
-rw-rw-r-- 1 test test 154 Feb 26 13:18 Makefile
-rw-rw-r-- 1 test test 47 Feb 26 13:18 modules.order
-rw-rw-r-- 1 test test 0 Feb 26 13:18 Module.symvers
-rw-rw-r-- 1 test test 820 Feb 26 13:18 linked_list.c
-rw-rw-r-- 1 test test 5880 Feb 26 13:18 linked_list.ko
-rw-rw-r-- 1 test test 47 Feb 26 13:18 linked_list.mod
-rw-rw-r-- 1 test test 919 Feb 26 13:18 linked_list.mod.c
-rw-rw-r-- 1 test test 3448 Feb 26 13:18 linked_list.mod.o
-rw-rw-r-- 1 test test 3320 Feb 26 13:18 linked_list.o
Run insmod to load the module.
$ sudo insmod ./linked_list.ko
Check the kernel messages to see if the kernel module is loaded or not.
$ dmesg
[ 6502.274246] Driver loaded
[ 6502.274247] Linked list: 2 -> NULL
[ 6502.274249] The last entry has value : 2
[ 6502.274249] The first entry is the last entry!
Run rmmod to unload the module.
$ sudo rmmod linked_list
Check dmesg to see if the module is unloaded from kernel.
$ dmesg
[ 6502.274246] Driver loaded
[ 6502.274247] Linked list: 2 -> NULL
[ 6502.274249] The last entry has value : 2
[ 6502.274249] The first entry is the last entry!
[ 6506.537914] Driver unloaded
API |
Learning |
---|---|
INIT_LIST_HEAD |
To initialize a list_head structure |
LIST_HEAD |
To initialize the list |
list_for_each_entry |
To iterate over list of given type |
list_add |
To insert a new entry after the specified head |
list_add_tail |
To insert a new entry before the specified head |
list_last_entry |
To retrieve the last list entry |
list_is_last |
To test whether a list is the last entry in list |
list_for_each_entry_safe |
To iterate over list of given type safe against removal of list entry |
list_del |
To delete entry from list |
Previous Chapters
Other Linked List topics
Next Chapter
Other Chapter