Module with Two Tasklet - spinlock irqsave
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/kthread.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/kfifo.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 - kfifo");
Intialize all the required variables and functions.
static DECLARE_KFIFO(my_fifo, char, FIFO_SIZE);
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);
DEFINE_SPINLOCK
is used to declare the spinlock variable.DECLARE_KFIFO
is a macro used to declare a kfifo and the associated buffer
Add the module init function which contains instructions executed once when the module is loaded.
static int __init tasklets_init(void)
{
pr_info("Driver Loaded...\n");
INIT_KFIFO(my_fifo);
tasklet_schedule(&tasklet1);
tasklet_schedule(&tasklet2);
return 0;
}
In this module init function,
initialize kfifo using
INIT_KFIFO
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)
{
pr_info("Driver Unloaded...\n");
}
Add the task handler APIs for both
tasklet1
,tasklet2
which will be executed once the tasklet is scheduled.
void tasklet_fun1(unsigned long data)
{
char val = 'A';
spin_lock_irqsave(&sp);
if (!kfifo_is_full(&my_fifo)) {
kfifo_in(&my_fifo, &val, sizeof(val));
pr_info("Tasklet function 1 : Enqueue : %c\n", val);
}
spin_unlock_irqrestore(&sp);
}
void tasklet_fun2(unsigned long data)
{
char val;
spin_lock_irqsave(&sp);
if (!kfifo_is_empty(&my_fifo)) {
kfifo_out(&my_fifo, &val, sizeof(val));
pr_info("Tasklet function 2 : Dequeue : %c\n", val);
}
spin_unlock_irqrestore(&sp);
}
In tasklet_fun1,
with the help of spinlocks, insert elements (enqueue) to kfifo using
kfifo_in
In takslet_fun2,
with the help of spinlocks, remove elements (dequeue) from kfifo using
kfifo_out
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/kthread.h>
9#include <linux/delay.h>
10#include <linux/interrupt.h>
11#include <linux/kfifo.h>
12#include <linux/slab.h>
13
14MODULE_LICENSE("GPL");
15MODULE_AUTHOR("Linux_usr");
16MODULE_DESCRIPTION("Tasklets - kfifo");
17
18#define FIFO_SIZE 2
19
20static DECLARE_KFIFO(my_fifo, char, FIFO_SIZE);
21DEFINE_SPINLOCK(sp);
22
23void tasklet_fun1(unsigned long data);
24void tasklet_fun2(unsigned long data);
25
26static DECLARE_TASKLET(tasklet1, (void *)tasklet_fun1, 0);
27static DECLARE_TASKLET(tasklet2, (void *)tasklet_fun2, 0);
28
29void tasklet_fun1(unsigned long data)
30{
31 char val = 'A';
32 unsigned long flags;
33
34 spin_lock_irqsave(&sp, flags);
35 if (!kfifo_is_full(&my_fifo)) {
36 kfifo_in(&my_fifo, &val, sizeof(val));
37 pr_info("Tasklet function 1 : Enqueue : %c\n", val);
38 }
39 spin_unlock_irqrestore(&sp, flags);
40}
41
42void tasklet_fun2(unsigned long data)
43{
44 char val;
45 unsigned long flags;
46
47 spin_lock_irqsave(&sp, flags);
48 if (!kfifo_is_empty(&my_fifo)) {
49 kfifo_out(&my_fifo, &val, sizeof(val));
50 pr_info("Tasklet function 2 : Dequeue : %c\n", val);
51 }
52 spin_unlock_irqrestore(&sp, flags);
53}
54
55static int __init tasklets_init(void)
56{
57 pr_info("Driver Loaded...\n");
58
59 INIT_KFIFO(my_fifo);
60
61 tasklet_schedule(&tasklet1);
62 tasklet_schedule(&tasklet2);
63
64 return 0;
65}
66
67static void __exit tasklets_exit(void)
68{
69 pr_info("Driver Unloaded...\n");
70}
71
72module_init(tasklets_init);
73module_exit(tasklets_exit);
1obj-m += tasklets.o
2
3KDIR = /lib/modules/$(shell uname -r)/build
4
5
6all:
7 make -C $(KDIR) M=$(shell pwd) modules
8
9clean:
10 make -C $(KDIR) M=$(shell 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
[ 3640.143058] Driver Loaded...
[ 3640.143202] Tasklet function 1 : Enqueue : A
[ 3640.143203] Tasklet function 2 : Dequeue : A
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
[ 3640.143058] Driver Loaded...
[ 3640.143202] Tasklet function 1 : Enqueue : A
[ 3640.143203] Tasklet function 2 : Dequeue : A
[ 3656.783751] Driver Unloaded...
List out the information about the kernel module using
modinfo
$ modinfo tasklets.ko
filename: tasklets.ko
description: Tasklets - kfifo
author: Linux_usr
license: GPL
srcversion: 8D40442BBC3BC6B4C2F0D24
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 |
spin_lock_irqsave |
Acquires given lock |
spin_unlock_irqrestore |
Releases given lock |
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 |
kfree |
free previously allocated memory by kmalloc |
tasklet_schedule |
to schedule the tasklet |
DECLARE_KFIFO |
macro to declare a kfifo and the associated buffer |
INIT_KFIFO |
to initialize kfifo |
kfifo_in |
enqueue elements to kfifo |
kfifo_out |
dequeue elemenst to kfifo |
kfifo_is_empty |
used to check if kfifo is empty, returns 1 if true otherwise 0 |
kfifo_is_full |
used to check if kfifo is full, returns 1 if true otherwise 0 |