Tasklet : Lock and Unlock

#

Version

Ubuntu

Ubuntu 22.10

Kernel

6.8.0

  • In this program, you are going to learn

  • How to create tasklet ?

  • What are the different ways to create tasklet ?

  • How to lock the tasklet ?

  • How to unlock the tasklet ?

  • How to kill the tasklet ?

#include <linux/interrupt.h>

#define from_tasklet(var, callback_tasklet, tasklet_fieldname)
  • Here is an example of how to use the API,

struct task *task_1 = from_tasklet(task_1, t, tasklet);
#include <linux/interrupt.h>

extern void tasklet_setup(struct tasklet_struct *t, void (*callback)(struct tasklet_struct *));
  • Here is an example of how to use the API,

tasklet_setup(&task_t->tasklet, tasklet_handler);
#include <linux/interrupt.h>

static inline int tasklet_trylock(struct tasklet_struct *t);
  • Here is an example of how to use the API,

tasklet_trylock(&task_t->tasklet);
#include <linux/interrupt.h>

static inline void tasklet_schedule(struct tasklet_struct *t);
  • Here is an example of how to use the API,

tasklet_schedule(&task_t->tasklet);
#include <linux/interrupt.h>

void tasklet_unlock(struct tasklet_struct *t);
  • Here is an example of how to use the API,

tasklet_unlock(&task_t->tasklet);
#include <linux/interrupt.h>

void tasklet_unlock_wait(struct tasklet_struct *t);
  • Here is an example of how to use the API,

tasklet_unlock_wait(&task_t->tasklet);
#include <linux/interrupt.h>

extern void tasklet_kill(struct tasklet_struct *t);
  • Here is an example of how to use the API,

tasklet_kill(&task_t->tasklet);
  • Here is the prototype of module paramter APIs

#include <linux/module.h>

#define MODULE_LICENSE(_license) MODULE_FILE MODULE_INFO(license, _license)
#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
  • where

    • MODULE_LICENSE: tells the kernel what license is used by our module.

    • MODULE_AUTHOR: denotes the author of this kernel module.

    • MODULE_DESCRIPTION: gives a basic idea about what the kernel module does.

    • These information can be found when modinfo command is used which lists out all these above mentioned information.

  • Here is the example of how to use the Module parameter APIs,

MODULE_LICENSE("GPL");
MODULE_AUTHOR("usr");
MODULE_DESCRIPTION("Tasklet");
  • Here is the prototype of the Driver entry point API’s

#include <linux/module.h>

#define module_init(x)      __initcall(x);
#define module_exit(x)      __exitcall(x);
  • where

    • module_init: driver initialization entry point which will be called at module insertion time.

    • module_exit: driver exit entry point which will be called during the removal of module.

    • x:
      • function to be run at module insertion for module_init function.

      • function to be run when driver is removed for module_exit function.

  • Here is an example of how to use the driver entry point API’s

module_init(task_init);
module_exit(task_exit);
  • In this example let’s see how to lock the tasklet using tasklet_trylock and execute it.

  • Include the follow header files(.h) to refer the API being used for the execution.

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
  • Add the following module macros to display information about the license, author and description about the module.

MODULE_LICENSE("GPL");
MODULE_AUTHOR("usr");
MODULE_DESCRIPTION("Tasklet");
  • Initialize the tasklet which we are going to create and use in this example

tasklet_setup(&task_t->tasklet, tasklet_handler);
  • This function executes once the tasklet is scheduled using tasklet_schedule.

void tasklet_handler(struct tasklet_struct *t)
{
        struct task *task_1 = from_tasklet(task_1, t, tasklet);

        pr_info("Inside tasklet handler function\n");
        pr_info("task_a : %d\n", task_1->task_a);
        pr_info("task_b : %d\n", task_1->task_b);
        pr_info("task_c : %c\n", task_1->task_c);
        pr_info("task_d : %s\n", task_1->task_d);
}
  • This function initializes tasklet dynamically using tasklet_setup.

  • lock the tasklet using tasklet_trylock.

  • schedules a tasklet using tasklet_schedule.

  • unlock the tasklet using tasklet_unlock.

void tasklet_start(void)
{
        task_t = kmalloc(sizeof(struct tasklet_struct *), GFP_KERNEL);
        if (task_t == NULL)
                pr_info("Cannot allocate memory\n");

        task_t->task_a = 10;
        task_t->task_b = 20;
        task_t->task_c = 'a';
        strncpy(task_t->task_d, "hello", sizeof(task_t->task_d));
        tasklet_setup(&task_t->tasklet, tasklet_handler);

        if (tasklet_trylock(&task_t->tasklet)) {
                pr_info("tasklet locked and will be scheduled!\n");
                tasklet_schedule(&task_t->tasklet);
                pr_info("tasklet scheduled!\n");
                tasklet_unlock(&task_t->tasklet);
        } else {
                pr_info("Tasklet is already running!\n");
        }
}
  • This function calls tasklet_start function, will be executed once the module is loaded into the linux kernel.

static int __init task_init(void)
{
        pr_info("driver loaded\n");
        tasklet_start();
        return 0;
}
  • This function kills tasklet and stops it’s execution.

void tasklet_stop(void)
{
        tasklet_kill(&task_t->tasklet);
        if (task_t != NULL)
                kfree(task_t);
}
  • This function calls tasklet_stop function, will be executed once the module is removed from the linux kernel

static void __exit task_exit(void)
{
        tasklet_stop();
        pr_info("driver unloaded\n");
}
  • Add the driver entry points which will be executed once the module is inserted or removed from the kernel.

module_init(task_init);
module_exit(task_exit);
 1#include <linux/init.h>
 2#include <linux/kernel.h>
 3#include <linux/module.h>
 4#include <linux/fs.h>
 5#include <linux/interrupt.h>
 6
 7MODULE_LICENSE("GPL");
 8MODULE_AUTHOR("Linux_usr");
 9MODULE_DESCRIPTION("Tasklet");
10
11void tasklet_handler(struct tasklet_struct *t);
12void tasklet_start(void);
13void tasklet_stop(void);
14
15struct task {
16	struct tasklet_struct tasklet;
17	int task_a;
18	int task_b;
19	char task_c;
20	char task_d[10];
21};
22
23struct task *task_t;
24
25/* tasklet_handler - it executes once the tasklet is scheduled using tasklet_schedule */
26void tasklet_handler(struct tasklet_struct *t)
27{
28	struct task *task_1 = from_tasklet(task_1, t, tasklet);
29
30	pr_info("Inside tasklet handler function\n");
31	pr_info("task_a : %d\n", task_1->task_a);
32	pr_info("task_b : %d\n", task_1->task_b);
33	pr_info("task_c : %c\n", task_1->task_c);
34	pr_info("task_d : %s\n", task_1->task_d);
35}
36
37/* tasklet_start - initializes tasklet dynamically using tasklet_setup
38 * lock the tasklet using tasklet_trylock
39 * schedules a tasklet using tasklet_schedule
40 * unlock the tasklet using tasklet_unlock
41 */
42void tasklet_start(void)
43{
44	task_t = kmalloc(sizeof(struct tasklet_struct *), GFP_KERNEL);
45	if (task_t == NULL)
46		pr_info("Cannot allocate memory\n");
47
48	task_t->task_a = 10;
49	task_t->task_b = 20;
50	task_t->task_c = 'a';
51	strncpy(task_t->task_d, "hello", sizeof(task_t->task_d));
52	tasklet_setup(&task_t->tasklet, tasklet_handler);
53
54	if (tasklet_trylock(&task_t->tasklet)) {
55		pr_info("tasklet locked and will be scheduled!\n");
56		tasklet_schedule(&task_t->tasklet);
57		pr_info("tasklet scheduled!\n");
58		tasklet_unlock(&task_t->tasklet);
59	} else {
60		pr_info("Tasklet is already running!\n");
61	}
62}
63
64/* task_init - calls tasklet_start function,
65 * will be executed once the module is loaded into the linux kernel
66 */
67static int __init task_init(void)
68{
69	pr_info("driver loaded\n");
70	tasklet_start();
71	return 0;
72}
73
74/* tasklet_stop - kills tasklet and stops it's execution */
75void tasklet_stop(void)
76{
77	tasklet_kill(&task_t->tasklet);
78	if (task_t != NULL)
79		kfree(task_t);
80}
81
82/* task_exit - calls tasklet_stop function,
83 * will be executed once the module is removed from the linux kernel
84 */
85static void __exit task_exit(void)
86{
87	tasklet_stop();
88	pr_info("driver unloaded\n");
89}
90
91module_init(task_init);
92module_exit(task_exit);
1obj-m += tasklet.o
2
3all:
4	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
5	sudo ../../checkpatch.pl --no-tree -f tasklet.c
6
7clean:
8	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
  • Run make to compile the kernel source and generate the .ko image.

$ make
make -C /lib/modules/6.8.0/build M=/home/arun/Desktop/kernel_api/tasklet/tasklet_lock_unlock/tc1 modules
make[1]: Entering directory '/home/arun/Desktop/kernel_api/linux-6.8'
  CC [M]  /home/arun/Desktop/kernel_api/tasklet/tasklet_lock_unlock/tc1/tasklet.o
  MODPOST /home/arun/Desktop/kernel_api/tasklet/tasklet_lock_unlock/tc1/Module.symvers
  CC [M]  /home/arun/Desktop/kernel_api/tasklet/tasklet_lock_unlock/tc1/tasklet.mod.o
  LD [M]  /home/arun/Desktop/kernel_api/tasklet/tasklet_lock_unlock/tc1/tasklet.ko
make[1]: Leaving directory '/home/arun/Desktop/kernel_api/linux-6.8'
  • Check if the .ko is generated or not using ls command.

$ ls -l
  total 388
  -rw-rw-r-- 1 arun arun    207 Jul 15 16:51 Makefile
  -rw-rw-r-- 1 arun arun     72 Jul 15 16:51 modules.order
  -rw-rw-r-- 1 arun arun      0 Jul 15 16:51 Module.symvers
  -rw-rw-r-- 1 arun arun   2287 Jun 25 12:53 tasklet.c
  -rw-rw-r-- 1 arun arun 184528 Jul 15 16:51 tasklet.ko
  -rw-rw-r-- 1 arun arun     72 Jul 15 16:51 tasklet.mod
  -rw-rw-r-- 1 arun arun   1202 Jul 15 16:51 tasklet.mod.c
  -rw-rw-r-- 1 arun arun 149488 Jul 15 16:51 tasklet.mod.o
  -rw-rw-r-- 1 arun arun  36408 Jul 15 16:51 tasklet.o
  • Run modinfo command to get the information about the kernel module.

$ modinfo tasklet.ko
filename:       /home/arun/Desktop/kernel_api/tasklet/tasklet_lock_unlock/tc1/tasklet.ko
description:    Tasklet
author:         Linux_usr
license:        GPL
srcversion:     11B7D8370432EEB50BD4DDF
depends:
retpoline:      Y
name:           tasklet
vermagic:       6.8.0 SMP preempt mod_unload modversions
  • insert the module using insmod command.

$ sudo insmod ./tasklet.ko
  • check if the module is loaded or not using lsmod command.

$ lsmod | grep tasklet
tasklet                12288  0
  • check for the kernel messages from init function and thread function once the module is loaded and thread is created.

$ sudo dmesg
[ 1754.975558] driver loaded
[ 1754.975564] tasklet locked and will be scheduled!
[ 1754.975574] tasklet scheduled!
[ 1754.975585] Inside tasklet handler function
[ 1754.975587] task_a : 10
[ 1754.975590] task_b : 20
[ 1754.975591] task_c : a
[ 1754.975593] task_d : hello
  • remove the module from kernel using rmmod command.

$ sudo rmmod tasklet
  • check if the module is still loaded after removing the kernel module using lsmod if it is not displayed in lsmod output it is verified that the module is removed successfully.

$ lsmod | grep tasklet
  • Check for kernel messages from exit function using dmesg command.

$ sudo dmesg
[534946.455200] driver unloaded
  • In this example let’s see how to disable the tasklet using tasklet_unlock_wait and execute it.

  • Include the follow header files(.h) to refer the API being used for the execution.

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
  • Add the following module macros to display information about the license, author and description about the module.

MODULE_LICENSE("GPL");
MODULE_AUTHOR("usr");
MODULE_DESCRIPTION("Tasklet");
  • Initialize the tasklet which we are going to create and use in this example

tasklet_setup(&task_t->my_tasklet, tasklet_handler);
  • This function executes once the tasklet is scheduled using tasklet_schedule.

void tasklet_handler(struct tasklet_struct *t)
{
        struct task *task_1 = from_tasklet(task_1, t, my_tasklet);

        pr_info("Inside tasklet handler function\n");
        pr_info("task_a : %d\n", task_1->task_a);
        pr_info("task_b : %d\n", task_1->task_b);
        pr_info("task_c : %c\n", task_1->task_c);
        pr_info("task_d : %s\n", task_1->task_d);
}
  • This function initializes the tasklet dynamically using tasklet_setup.

  • Disabling the tasklet using tasklet_disable_in_atomic.

  • Enabling the tasklet using tasklet_enable.

  • schedules a tasklet using tasklet_schedule.

void tasklet_start(void)
{
        task_t = kmalloc(sizeof(struct tasklet_struct *), GFP_KERNEL);
        if (task_t == NULL)
                pr_info("Cannot allocate memory\n");

        task_t->task_a = 10;
        task_t->task_b = 20;
        task_t->task_c = 'a';
        strncpy(task_t->task_d, "hello", sizeof(task_t->task_d));
        tasklet_setup(&task_t->tasklet, tasklet_handler);

        if (tasklet_trylock(&task_t->tasklet)) {
                pr_info("tasklet locked and will be scheduled!\n");
                tasklet_schedule(&task_t->tasklet);
                pr_info("tasklet scheduled!\n");
                tasklet_unlock(&task_t->tasklet);
        } else {
                pr_info("Tasklet is already running!\n");
        }
}
  • This function calls tasklet_start function, will be executed once the module is loaded into the linux kernel.

static int __init task_init(void)
{
        pr_info("driver loaded\n");
        tasklet_start();
        return 0;
}
  • This function kills tasklet and stops it’s execution.

void tasklet_stop(void)
{
        tasklet_unlock_wait(&task_t->tasklet);
        tasklet_kill(&task_t->tasklet);
        if (task_t != NULL)
                kfree(task_t);
}
  • This function calls tasklet_stop function, will be executed once the module is removed from the linux kernel

static void __exit task_exit(void)
{
        tasklet_stop();
        pr_info("driver unloaded\n");
}
  • Add the driver entry points which will be executed once the module is inserted or removed from the kernel.

module_init(task_init);
module_exit(task_exit);
 1#include <linux/init.h>
 2#include <linux/kernel.h>
 3#include <linux/module.h>
 4#include <linux/fs.h>
 5#include <linux/interrupt.h>
 6
 7MODULE_LICENSE("GPL");
 8MODULE_AUTHOR("Linux_usr");
 9MODULE_DESCRIPTION("Tasklet");
10
11void tasklet_handler(struct tasklet_struct *t);
12void tasklet_start(void);
13void tasklet_stop(void);
14
15struct task {
16	struct tasklet_struct tasklet;
17	int task_a;
18	int task_b;
19	char task_c;
20	char task_d[10];
21};
22
23struct task *task_t;
24
25/* tasklet_handler - it executes once the tasklet is scheduled using tasklet_schedule */
26void tasklet_handler(struct tasklet_struct *t)
27{
28	struct task *task_1 = from_tasklet(task_1, t, tasklet);
29
30	pr_info("Inside tasklet handler function\n");
31	pr_info("task_a : %d\n", task_1->task_a);
32	pr_info("task_b : %d\n", task_1->task_b);
33	pr_info("task_c : %c\n", task_1->task_c);
34	pr_info("task_d : %s\n", task_1->task_d);
35}
36
37/* tasklet_start - initializes tasklet dynamically using tasklet_setup
38 * lock the tasklet using tasklet_trylock
39 * schedules a tasklet using tasklet_schedule
40 * unlock the tasklet using tasklet_unlock
41 */
42void tasklet_start(void)
43{
44	task_t = kmalloc(sizeof(struct tasklet_struct *), GFP_KERNEL);
45	if (task_t == NULL)
46		pr_info("Cannot allocate memory\n");
47
48	task_t->task_a = 10;
49	task_t->task_b = 20;
50	task_t->task_c = 'a';
51	strncpy(task_t->task_d, "hello", sizeof(task_t->task_d));
52	tasklet_setup(&task_t->tasklet, tasklet_handler);
53
54	if (tasklet_trylock(&task_t->tasklet)) {
55		pr_info("tasklet locked and will be scheduled!\n");
56		tasklet_schedule(&task_t->tasklet);
57		pr_info("tasklet scheduled!\n");
58		tasklet_unlock(&task_t->tasklet);
59	} else {
60		pr_info("Tasklet is already running!\n");
61	}
62}
63
64/* task_init - calls tasklet_start function,
65 * will be executed once the module is loaded into the linux kernel
66 */
67static int __init task_init(void)
68{
69	pr_info("driver loaded\n");
70	tasklet_start();
71	return 0;
72}
73
74/* tasklet_stop - ensure the tasklet has finished executing using tasklet_unlock_wait
75 * kills tasklet and stops it's execution
76 */
77void tasklet_stop(void)
78{
79	tasklet_unlock_wait(&task_t->tasklet);
80	tasklet_kill(&task_t->tasklet);
81	if (task_t != NULL)
82		kfree(task_t);
83}
84
85/* task_exit - calls tasklet_stop function,
86 * will be executed once the module is removed from the linux kernel
87 */
88static void __exit task_exit(void)
89{
90	tasklet_stop();
91	pr_info("driver unloaded\n");
92}
93
94module_init(task_init);
95module_exit(task_exit);
1obj-m += tasklet.o
2
3all:
4	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
5	sudo ../../checkpatch.pl --no-tree -f tasklet.c
6
7clean:
8	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
  • Run make to compile the kernel source and generate the .ko image.

$ make
make -C /lib/modules/6.8.0/build M=/home/arun/Desktop/kernel_api/tasklet/tasklet_lock_unlock/tc2 modules
make[1]: Entering directory '/home/arun/Desktop/kernel_api/linux-6.8'
  CC [M]  /home/arun/Desktop/kernel_api/tasklet/tasklet_lock_unlock/tc2/tasklet.o
  MODPOST /home/arun/Desktop/kernel_api/tasklet/tasklet_lock_unlock/tc2/Module.symvers
  CC [M]  /home/arun/Desktop/kernel_api/tasklet/tasklet_lock_unlock/tc2/tasklet.mod.o
  LD [M]  /home/arun/Desktop/kernel_api/tasklet/tasklet_lock_unlock/tc2/tasklet.ko
make[1]: Leaving directory '/home/arun/Desktop/kernel_api/linux-6.8'
  • Check if the .ko is generated or not using ls command.

$ ls -l
total 388
-rw-rw-r-- 1 arun arun    206 Jun 25 12:55 Makefile
-rw-rw-r-- 1 arun arun     72 Jul 15 16:58 modules.order
-rw-rw-r-- 1 arun arun      0 Jul 15 16:58 Module.symvers
-rw-rw-r-- 1 arun arun   2399 Jun 25 12:58 tasklet.c
-rw-rw-r-- 1 arun arun 184912 Jul 15 16:58 tasklet.ko
-rw-rw-r-- 1 arun arun     72 Jul 15 16:58 tasklet.mod
-rw-rw-r-- 1 arun arun   1242 Jul 15 16:58 tasklet.mod.c
-rw-rw-r-- 1 arun arun 149552 Jul 15 16:58 tasklet.mod.o
-rw-rw-r-- 1 arun arun  36784 Jul 15 16:58 tasklet.o
  • Run modinfo command to get the information about the kernel module.

$ modinfo tasklet.ko
filename:       /home/arun/Desktop/kernel_api/tasklet/tasklet_lock_unlock/tc2/tasklet.ko
description:    Tasklet
author:         Linux_usr
license:        GPL
srcversion:     7B366B9556F3B5AC35F3411
depends:
retpoline:      Y
name:           tasklet
vermagic:       6.8.0 SMP preempt mod_unload modversions
  • insert the module using insmod command.

$ sudo insmod ./tasklet.ko
  • check if the module is loaded or not using lsmod command.

$ lsmod | grep tasklet
tasklet                12288  0
  • check for the kernel messages from init function and thread function once the module is loaded and thread is created.

$ sudo dmesg
[ 2116.050510] driver loaded
[ 2116.050512] tasklet locked and will be scheduled!
[ 2116.050514] tasklet scheduled!
[ 2116.050518] Inside tasklet handler function
[ 2116.050518] task_a : 10
[ 2116.050519] task_b : 20
[ 2116.050519] task_c : a
[ 2116.050520] task_d : hello
  • remove the module from kernel using rmmod command.

$ sudo rmmod tasklet
  • check if the module is still loaded after removing the kernel module using lsmod if it is not displayed in lsmod output it is verified that the module is removed successfully.

$ lsmod | grep tasklet
  • Check for kernel messages from exit function using dmesg command.

$ sudo dmesg
[534946.455200] driver unloaded