Module with Two Tasklet - spinlock
In this program, you are going to learn
How to schedule the tasklet ?
How to use below APIs ?
Here is the explanation of the program part by part
Include all the required header files to refer to the APIs used in the program.
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/slab.h>
Add the macro modules to list out the information about the module such as license, description and author.
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux_usr");
MODULE_DESCRIPTION("Tasklets - Spinlock");
Intialize all the required variables and functions.
DEFINE_SPINLOCK(sp);
void tasklet_fun1(unsigned long data);
void tasklet_fun2(unsigned long data);
static DECLARE_TASKLET(tasklet1, (void *)tasklet_fun1, 0);
static DECLARE_TASKLET(tasklet2, (void *)tasklet_fun2, 0);
struct node {
int data;
struct list_head list;
};
LIST_HEAD(my_list);
DEFINE_SPINLOCK
is used to declare the spinlock variable.LIST_HEAD
is used to initialize a list head structure.
Add the module init function which contains instructions executed once when the module is loaded.
static int __init tasklets_init(void)
{
struct node *node1;
struct node *node2;
pr_info("Driver Loaded...\n");
node1 = kmalloc(sizeof(struct node), GFP_KERNEL);
node1->data = 1;
INIT_LIST_HEAD(&node1->list);
list_add_tail(&node1->list, &my_list);
node2 = kmalloc(sizeof(struct node), GFP_KERNEL);
node2->data = 2;
INIT_LIST_HEAD(&node2->list);
list_add_tail(&node2->list, &my_list);
tasklet_schedule(&tasklet1);
tasklet_schedule(&tasklet2);
return 0;
}
In this module init function,
initialize two nodes
node1
,node2
and allocate memory dynamically.add the nodes to the list.
initiate tasklet with
tasklet_schedule
Add the instructions for module exit function which will be executed once the module is unloaded from kernel.
static void __exit tasklets_exit(void)
{
struct node *curr_node, *next_node;
list_for_each_entry_safe(curr_node, next_node, &my_list, list) {
list_del(&curr_node->list);
kfree(curr_node);
}
pr_info("Driver Unloaded...\n");
}
Delete and free all the entries from the list.
Add the task handler APIs for both
tasklet1
,tasklet2
which will be executed once the tasklet is scheduled.
void tasklet_fun1(unsigned long data)
{
struct node *new_node;
spin_lock(&sp);
list_for_each_entry(new_node, &my_list, list) {
new_node->data++;
pr_info("Executing tasklet function 1 : %d\n", new_node->data);
}
spin_unlock(&sp);
}
void tasklet_fun2(unsigned long data)
{
struct node *new_node;
spin_lock(&sp);
list_for_each_entry(new_node, &my_list, list) {
new_node->data++;
pr_info("Executing tasklet function 2 : %d\n", new_node->data);
}
spin_unlock(&sp);
}
In this tasklet handler APIs,
Add the node for list by locking and unlocking with the help of spinlock.
locking and unlocking can be done with the help of
spin_lock
spin_unlock
respectively.
Add the init and exit functions in
module_init
andmodule_exit
respectively.
module_init(tasklets_init);
module_exit(tasklets_exit);
1#include <linux/init.h>
2#include <linux/kernel.h>
3#include <linux/module.h>
4#include <linux/cdev.h>
5#include <linux/device.h>
6#include <linux/fs.h>
7#include <linux/uaccess.h>
8#include <linux/delay.h>
9#include <linux/interrupt.h>
10#include <linux/list.h>
11#include <linux/slab.h>
12
13MODULE_LICENSE("GPL");
14MODULE_AUTHOR("Linux_usr");
15MODULE_DESCRIPTION("Tasklets - Spinlock");
16
17DEFINE_SPINLOCK(sp);
18
19void tasklet_fun1(unsigned long data);
20void tasklet_fun2(unsigned long data);
21
22static DECLARE_TASKLET(tasklet1, (void *)tasklet_fun1, 0);
23static DECLARE_TASKLET(tasklet2, (void *)tasklet_fun2, 0);
24
25struct node {
26 int data;
27 struct list_head list;
28};
29
30LIST_HEAD(my_list);
31
32void tasklet_fun1(unsigned long data)
33{
34 struct node *new_node;
35
36 spin_lock(&sp);
37 list_for_each_entry(new_node, &my_list, list) {
38 new_node->data++;
39 pr_info("Executing tasklet function 1 : %d\n", new_node->data);
40 }
41 spin_unlock(&sp);
42}
43
44void tasklet_fun2(unsigned long data)
45{
46 struct node *new_node;
47
48 spin_lock(&sp);
49 list_for_each_entry(new_node, &my_list, list) {
50 new_node->data++;
51 pr_info("Executing tasklet function 2 : %d\n", new_node->data);
52 }
53 spin_unlock(&sp);
54}
55
56static int __init tasklets_init(void)
57{
58 struct node *node1;
59 struct node *node2;
60
61 pr_info("Driver Loaded...\n");
62
63 node1 = kmalloc(sizeof(struct node), GFP_KERNEL);
64 node1->data = 1;
65 INIT_LIST_HEAD(&node1->list);
66 list_add_tail(&node1->list, &my_list);
67
68 node2 = kmalloc(sizeof(struct node), GFP_KERNEL);
69 node2->data = 2;
70 INIT_LIST_HEAD(&node2->list);
71 list_add_tail(&node2->list, &my_list);
72
73 tasklet_schedule(&tasklet1);
74 tasklet_schedule(&tasklet2);
75
76 return 0;
77}
78
79static void __exit tasklets_exit(void)
80{
81 struct node *curr_node, *next_node;
82
83 list_for_each_entry_safe(curr_node, next_node, &my_list, list) {
84 list_del(&curr_node->list);
85 kfree(curr_node);
86 }
87 pr_info("Driver Unloaded...\n");
88}
89
90module_init(tasklets_init);
91module_exit(tasklets_exit);
1obj-m += tasklets.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 kernel module.
$ make
make -C /lib/modules/5.4.0-150-generic/build M=$HOME/kernel_tasklets modules
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-150-generic'
CC [M] $HOME/kernel_tasklets/tasklets.o
Building modules, stage 2.
MODPOST 1 modules
CC [M] $HOME/kernel_tasklets/tasklets.mod.o
LD [M] $HOME/kernel_tasklets/tasklets.ko
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-150-generic'
Check if tasklets.ko is generated or not using ls command.
$ 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 tasklets.c
-rw-rw-r-- 1 test test 5880 Feb 26 13:18 tasklets.ko
-rw-rw-r-- 1 test test 47 Feb 26 13:18 tasklets.mod
-rw-rw-r-- 1 test test 919 Feb 26 13:18 tasklets.mod.c
-rw-rw-r-- 1 test test 3448 Feb 26 13:18 tasklets.mod.o
-rw-rw-r-- 1 test test 3320 Feb 26 13:18 tasklets.o
Run insmod command to load the module in kernel.
$ sudo insmod ./tasklets.ko
Check if the module is loaded or not by seeing the kernel messages.
$ dmesg
[33238.609795] Driver Loaded...
[33238.609807] Executing tasklet function 1 : 2
[33238.609807] Executing tasklet function 1 : 3
[33238.609808] Executing tasklet function 2 : 3
[33238.609808] Executing tasklet function 2 : 4
This can also be verified by using the lsmod command.
$ lsmod | grep tasklets
tasklets 16384 0
Unload the module by using rmmod command.
$ sudo rmmod tasklets
Check kernel messages to verify if the module is unloaded or not.
$ dmesg
[33238.609795] Driver Loaded...
[33238.609807] Executing tasklet function 1 : 2
[33238.609807] Executing tasklet function 1 : 3
[33238.609808] Executing tasklet function 2 : 3
[33238.609808] Executing tasklet function 2 : 4
[33252.066977] Driver Unloaded...
List out the information about the kernel module using
modinfo
$ modinfo tasklets.ko
filename: tasklets.ko
description: Tasklets - Spinlock
author: Linux_usr
license: GPL
srcversion: 13DF48B64B5E046B051D5E4
depends:
retpoline: Y
name: tasklets
vermagic: 5.4.0-150-generic SMP mod_unload modversions
API |
Learning |
---|---|
MODULE_DESCRIPTION |
used to describe what the module does |
DEFINE_SPINLOCK |
To declare a spinlock variable and initialize it in one line |
DECLARE_TASKLET |
To declare tasklet variable |
LIST_HEAD |
A list is headed by a structure defined by the LIST_HEAD macro |
spin_lock |
Acquires given lock |
list_for_each_entry |
iterate over list of given type |
spin_unlock |
Releases given lock |
INIT_LIST_HEAD |
Initialize a list_head structure |
list_add_tail |
add a new entry |
kmalloc |
kernel memory allocation function |
IS_ERR |
used to check, Returns non-0 value if the ptr is an error, Otherwise 0 if it’s not an error |
pr_alert |
Print an alert-level message |
PTR_ERR |
used to print, Current value of the pointer |
list_for_each_entry_safe |
iterate over list of given type safe against removal of list entry |
list_del |
deletes entry from list |
kfree |
free previously allocated memory by kmalloc |
tasklet_schedule |
to schedule the tasklet |