Module with Two Tasklet - spinlock

  • 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/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(&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(&sp);
}

void tasklet_fun2(unsigned long data)
{
    char val;

    spin_lock(&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(&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 and module_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
33	spin_lock(&sp);
34	if (!kfifo_is_full(&my_fifo)) {
35		kfifo_in(&my_fifo, &val, sizeof(val));
36		pr_info("Tasklet function 1 : Enqueue : %c\n",  val);
37	}
38	spin_unlock(&sp);
39}
40
41void tasklet_fun2(unsigned long data)
42{
43	char val;
44
45	spin_lock(&sp);
46	if (!kfifo_is_empty(&my_fifo)) {
47		kfifo_out(&my_fifo, &val, sizeof(val));
48		pr_info("Tasklet function 2 : Dequeue : %c\n", val);
49	}
50	spin_unlock(&sp);
51}
52
53static int __init tasklets_init(void)
54{
55	pr_info("Driver Loaded...\n");
56
57	INIT_KFIFO(my_fifo);
58
59	tasklet_schedule(&tasklet1);
60	tasklet_schedule(&tasklet2);
61
62	return 0;
63}
64
65static void __exit tasklets_exit(void)
66{
67	pr_info("Driver Unloaded...\n");
68}
69
70module_init(tasklets_init);
71module_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
[ 3002.454606] Driver Loaded...
[ 3002.454613] Tasklet function 1 : Enqueue : A
[ 3002.454614] 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
[ 3002.454606] Driver Loaded...
[ 3002.454613] Tasklet function 1 : Enqueue : A
[ 3002.454614] Tasklet function 2 : Dequeue : A
[ 3012.638516] 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:     B4F929D787583191F3818BF
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

Acquires given lock

spin_unlock

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