Module with Two Tasklet - semaphore
In this program, you are going to learn
How to schedule the tasklet ?
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>
#include <linux/semaphore.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 - semaphore");
Intialize all the required variables and functions.
static struct semaphore sema;
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);
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);
sema_init(&sema, 1);
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;
down(&sema);
list_for_each_entry(new_node, &my_list, list) {
new_node->data++;
pr_info("Executing tasklet function 1 : %d\n", new_node->data);
}
up(&sema);
}
void tasklet_fun2(unsigned long data)
{
struct node *new_node;
down(&sema);
list_for_each_entry(new_node, &my_list, list) {
new_node->data++;
pr_info("Executing tasklet function 2 : %d\n", new_node->data);
}
up(&sema);
}
In this tasklet handler APIs,
Add the node for list by locking and unlocking with the help of semaphore.
locking and unlocking can be done with the help of
down
up
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#include <linux/semaphore.h>
13
14MODULE_LICENSE("GPL");
15MODULE_AUTHOR("Linux_usr");
16MODULE_DESCRIPTION("Tasklets - Semaphore");
17
18static struct semaphore sema;
19
20void tasklet_fun1(unsigned long data);
21void tasklet_fun2(unsigned long data);
22
23static DECLARE_TASKLET(tasklet1, (void *)tasklet_fun1, 0);
24static DECLARE_TASKLET(tasklet2, (void *)tasklet_fun2, 0);
25
26struct node {
27 int data;
28 struct list_head list;
29};
30
31LIST_HEAD(my_list);
32
33void tasklet_fun1(unsigned long data)
34{
35 struct node *new_node;
36
37 down(&sema);
38 list_for_each_entry(new_node, &my_list, list) {
39 new_node->data++;
40 pr_info("Executing tasklet function 1 : %d\n", new_node->data);
41 }
42 up(&sema);
43}
44
45void tasklet_fun2(unsigned long data)
46{
47 struct node *new_node;
48
49 down(&sema);
50 list_for_each_entry(new_node, &my_list, list) {
51 new_node->data++;
52 pr_info("Executing tasklet function 2 : %d\n", new_node->data);
53 }
54 up(&sema);
55}
56
57static int __init tasklets_init(void)
58{
59 struct node *node1;
60 struct node *node2;
61
62 pr_info("Driver Loaded...\n");
63
64 node1 = kmalloc(sizeof(struct node), GFP_KERNEL);
65 node1->data = 1;
66 INIT_LIST_HEAD(&node1->list);
67 list_add_tail(&node1->list, &my_list);
68
69 sema_init(&sema, 1);
70
71 node2 = kmalloc(sizeof(struct node), GFP_KERNEL);
72 node2->data = 2;
73 INIT_LIST_HEAD(&node2->list);
74 list_add_tail(&node2->list, &my_list);
75
76 tasklet_schedule(&tasklet1);
77 tasklet_schedule(&tasklet2);
78
79 return 0;
80}
81
82static void __exit tasklets_exit(void)
83{
84 struct node *curr_node, *next_node;
85
86 list_for_each_entry_safe(curr_node, next_node, &my_list, list) {
87 list_del(&curr_node->list);
88 kfree(curr_node);
89 }
90 pr_info("Driver Unloaded...\n");
91}
92
93module_init(tasklets_init);
94module_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
[34802.992048] Driver Loaded...
[34802.992060] Executing tasklet function 1 : 2
[34802.992061] Executing tasklet function 1 : 3
[34802.992061] Executing tasklet function 2 : 3
[34802.992062] 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
[34802.992048] Driver Loaded...
[34802.992060] Executing tasklet function 1 : 2
[34802.992061] Executing tasklet function 1 : 3
[34802.992061] Executing tasklet function 2 : 3
[34802.992062] Executing tasklet function 2 : 4
[34812.872064] Driver Unloaded...
List out the information about the kernel module using
modinfo
$ modinfo tasklets.ko
filename: tasklets.ko
description: Tasklets - semaphore
author: Linux_usr
license: GPL
srcversion: 17465E688EC46A276B8B348
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 |
DECLARE_TASKLET |
To declare tasklet variable |
sema_init |
To initialize semaphore variable |
LIST_HEAD |
A list is headed by a structure defined by the LIST_HEAD macro |
down |
Acquires given lock |
list_for_each_entry |
iterate over list of given type |
up |
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 |