Module with Two Timers - spinlock irqsave
In this program, you are going to learn
How to schedule the timer ?
How to use below APIs ?
Here is the explanation of the source code.
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
Include all the headers file to refer the APIs used in this program.
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux_usr");
MODULE_DESCRIPTION("Two Timers with spinlock");
Add the modules macro which gives information about the license, author and description of the modules.
struct node {
int data;
struct list_head list;
};
LIST_HEAD(my_list);
DEFINE_SPINLOCK(sp);
static struct timer_list timer1;
static struct timer_list timer2;
Initialize all the variables and functions used in this program.
static int __init timer_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);
timer_setup(&timer1, timer1_callback, 0);
mod_timer(&timer1, jiffies + msecs_to_jiffies(TIMEOUT));
timer_setup(&timer2, timer2_callback, 0);
mod_timer(&timer2, jiffies + msecs_to_jiffies(TIMEOUT));
return 0;
}
Create module init function which is exectued once the module is loaded to kernel.
static void __exit timer_exit(void)
{
del_timer(&timer1);
del_timer(&timer2);
pr_info("Driver Unloaded...\n");
}
Create module exit function which will be executed once the module is unloaded from kernel.
static void timer1_callback(struct timer_list *timer)
{
struct node *new_node;
spin_lock_irqsave(&sp, flags);
new_node = kmalloc(sizeof(struct node), GFP_KERNEL);
if (!new_node) {
pr_err("Failed to allocate memory for new_node\n");
return;
}
list_for_each_entry(new_node, &my_list, list) {
new_node->data++;
pr_info("Executing timer function 1 : %d\n", new_node->data);
}
spin_unlock_irqrestore(&sp, flags);
mod_timer(&timer1, jiffies + msecs_to_jiffies(TIMEOUT));
}
static void timer2_callback(struct timer_list *timer)
{
struct node *new_node;
spin_lock_irqsave(&sp, flags);
list_for_each_entry(new_node, &my_list, list) {
new_node->data++;
pr_info("Executing timer function 2 : %d\n", new_node->data);
}
spin_unlock_irqrestore(&sp, flags);
mod_timer(&timer2, jiffies + msecs_to_jiffies(TIMEOUT));
}
Create the timer APIs which will be executed once the work is scheduled.
module_init(timer_init);
module_exit(timer_exit);
Add the module init and exit functions which needs to executed once the module is loaded and unloaded.
1#include <linux/init.h>
2#include <linux/kernel.h>
3#include <linux/module.h>
4#include <linux/fs.h>
5#include <linux/cdev.h>
6#include <linux/device.h>
7#include <linux/uaccess.h>
8#include <linux/delay.h>
9#include <linux/list.h>
10#include <linux/slab.h>
11#include <linux/timer.h>
12#include <linux/jiffies.h>
13
14#define TIMEOUT 5000
15
16MODULE_LICENSE("GPL");
17MODULE_AUTHOR("Linux_usr");
18MODULE_DESCRIPTION("Two Timers with spinlock");
19
20struct node {
21 int data;
22 struct list_head list;
23};
24
25LIST_HEAD(my_list);
26
27DEFINE_SPINLOCK(sp);
28
29static struct timer_list timer1;
30static struct timer_list timer2;
31
32
33static void timer1_callback(struct timer_list *timer)
34{
35 unsigned long flags;
36 struct node *new_node;
37
38 spin_lock_irqsave(&sp, flags);
39 new_node = kmalloc(sizeof(struct node), GFP_KERNEL);
40 if (!new_node) {
41 pr_err("Failed to allocate memory for new_node\n");
42 return;
43 }
44 list_for_each_entry(new_node, &my_list, list) {
45 new_node->data++;
46 pr_info("Executing timer function 1 : %d\n", new_node->data);
47 }
48 spin_unlock_irqrestore(&sp, flags);
49
50 mod_timer(&timer1, jiffies + msecs_to_jiffies(TIMEOUT));
51}
52
53static void timer2_callback(struct timer_list *timer)
54{
55 unsigned long flags;
56 struct node *new_node;
57
58 spin_lock_irqsave(&sp, flags);
59 list_for_each_entry(new_node, &my_list, list) {
60 new_node->data++;
61 pr_info("Executing timer function 2 : %d\n", new_node->data);
62 }
63 spin_unlock_irqrestore(&sp, flags);
64 mod_timer(&timer2, jiffies + msecs_to_jiffies(TIMEOUT));
65}
66
67static int __init timer_init(void)
68{
69 struct node *node1;
70 struct node *node2;
71
72 pr_info("Driver Loaded...\n");
73
74 node1 = kmalloc(sizeof(struct node), GFP_KERNEL);
75 node1->data = 1;
76 INIT_LIST_HEAD(&node1->list);
77 list_add_tail(&node1->list, &my_list);
78
79 node2 = kmalloc(sizeof(struct node), GFP_KERNEL);
80 node2->data = 2;
81 INIT_LIST_HEAD(&node2->list);
82 list_add_tail(&node2->list, &my_list);
83
84 timer_setup(&timer1, timer1_callback, 0);
85 mod_timer(&timer1, jiffies + msecs_to_jiffies(TIMEOUT));
86
87 timer_setup(&timer2, timer2_callback, 0);
88 mod_timer(&timer2, jiffies + msecs_to_jiffies(TIMEOUT));
89
90 return 0;
91}
92
93static void __exit timer_exit(void)
94{
95 del_timer(&timer1);
96 del_timer(&timer2);
97 pr_info("Driver Unloaded...\n");
98
99}
100
101module_init(timer_init);
102module_exit(timer_exit);
1obj-m += timer.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 module.
$make
make -C /lib/modules/5.4.0-150-generic/build M=$HOME/kernel_timer modules
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-150-generic'
CC [M] $HOME/kernel_timer/timer.o
Building modules, stage 2.
MODPOST 1 modules
CC [M] $HOME/kernel_timer/timer.mod.o
LD [M] $HOME/kernel_timer/timer.ko
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-150-generic'
Run lsmod to check if timer.ko is generated or not.
$ 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 timer.c
-rw-rw-r-- 1 test test 5880 Feb 26 13:18 timer.ko
-rw-rw-r-- 1 test test 47 Feb 26 13:18 timer.mod
-rw-rw-r-- 1 test test 919 Feb 26 13:18 timer.mod.c
-rw-rw-r-- 1 test test 3448 Feb 26 13:18 timer.mod.o
-rw-rw-r-- 1 test test 3320 Feb 26 13:18 timer.o
Run insmod to load the module to kernel.
$ sudo insmod ./timer.ko
Check the kernel messages to see if the module is loaded or not.
$ dmesg
[94753.049905] Driver Loaded...
[94758.275106] Executing timer function 2 : 2
[94758.275110] Executing timer function 2 : 3
[94758.275145] Executing timer function 1 : 3
[94758.275148] Executing timer function 1 : 4
[94763.395185] Executing timer function 1 : 4
[94763.395188] Executing timer function 1 : 5
[94763.395206] Executing timer function 2 : 5
[94763.395207] Executing timer function 2 : 6
[94768.515256] Executing timer function 2 : 6
[94768.515258] Executing timer function 2 : 7
[94768.515260] Executing timer function 1 : 7
[94768.515261] Executing timer function 1 : 8
[94773.635390] Executing timer function 1 : 8
[94773.635394] Executing timer function 1 : 9
[94773.635433] Executing timer function 2 : 9
[94773.635440] Executing timer function 2 : 10
Check the module is loaded using lsmod command
$ lsmod | grep timer
timer 16384 0
Remove the kernel module using rmmod command.
$ sudo rmmod timer
Check the kernel messages to see if the module is unloaded or not.
$ dmesg
[94753.049905] Driver Loaded...
[94758.275106] Executing timer function 2 : 2
[94758.275110] Executing timer function 2 : 3
[94758.275145] Executing timer function 1 : 3
[94758.275148] Executing timer function 1 : 4
[94763.395185] Executing timer function 1 : 4
[94763.395188] Executing timer function 1 : 5
[94763.395206] Executing timer function 2 : 5
[94763.395207] Executing timer function 2 : 6
[94768.515256] Executing timer function 2 : 6
[94768.515258] Executing timer function 2 : 7
[94768.515260] Executing timer function 1 : 7
[94768.515261] Executing timer function 1 : 8
[94773.635390] Executing timer function 1 : 8
[94773.635394] Executing timer function 1 : 9
[94773.635433] Executing timer function 2 : 9
[94773.635440] Executing timer function 2 : 10
[94776.568138] Driver Unloaded...
Run modinfo to get information about the kernel module.
$ modinfo timer.ko
filename: timer.ko
description: Two timers with spinlock
author: Linux_usr
license: GPL
srcversion: 5F51A1882365F26AE733170
depends:
retpoline: Y
name: timer
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 |
LIST_HEAD |
A list is headed by a structure defined by the LIST_HEAD macro |
spin_lock_irqsave |
Acquires given lock |
list_for_each_entry |
iterate over list of given type |
spin_unlock_irqrestore |
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 |
timer_setup |
To initialize the timer |
mod_timer |
To modify a timer’s timeout |
del_timer |
To stop a running timer |
msecs_to_jiffies |
To convert milliseconds |