Start Timer

#

Version

Ubuntu

Ubuntu 22.10

Kernel

6.8.0

  • In this program, you are going to learn

  • How to create timer ?

  • How to start the timer ?

  • How to set up the timer ?

  • How to stop the timer ?

  • Here is the function prototype of the API: from_timer

#include <linux/timer.h>

#define from_timer(var, callback_timer, timer_fieldname)
  • Here is the function prototype of the API: add_timer

#include <linux/timer.h>

extern void add_timer(struct timer_list *timer);
  • Here is the function prototype of the API: del_timer

#include <linux/timer.h>

static inline int del_timer(struct timer_list *timer);
  • Here is the function prototype of the API: timer_setup

#include <linux/timer.h>

#define timer_setup(timer, callback, flags)
  • Here is the function prototype of the API: mod_timer

#include <linux/timer.h>

extern int mod_timer(struct timer_list *timer, unsigned long expires);
#include <linux/timer.h>

extern void add_timer_on(struct timer_list *timer, int cpu);
  • 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("Timer");
  • 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 start the timer using add_timer 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/timer.h>
#include <linux/jiffies.h>
#include <linux/err.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("Timer");
  • Setting up the timer which we are going to create and use in this example

timer_setup(&drv_var.my_timer, timer_callback, 0);
  • This function executes once the timer expires.

static void timer_callback(struct timer_list * t)
{
        pr_info("Inside Timer Callback function\n");

        struct my_drv_info * my_drv_info_ptr = from_timer(my_drv_info_ptr, t, my_timer);
        pr_info("%s : data_a : %d\n", __func__, my_drv_info_ptr->data_a);
        pr_info("%s : data_b : %d\n", __func__, my_drv_info_ptr->data_b);
        pr_info("%s : data_c : %c\n", __func__, my_drv_info_ptr->data_c);
        pr_info("%s : data_d : %s\n", __func__, my_drv_info_ptr->data_d);
        mod_timer(&my_drv_info_ptr->my_timer, jiffies + msecs_to_jiffies(TIMEOUT));
}
  • This function setup the timer to call timer_callback() using timer_setup.

  • Starts timer using add_timer.

void timer_start(void)
{
        drv_var.data_a = 10;
        drv_var.data_b = 20;
        drv_var.data_c = 'a';
        strncpy(drv_var.data_d, "hello", sizeof(drv_var.data_d));

        timer_setup(&drv_var.my_timer, timer_callback, 0);
        add_timer(&drv_var.my_timer);
}
  • This function calls timer_start function, will be executed once the module is loaded into the linux kernel.

static int __init timer_init(void)
{
        pr_info("Inside timer_init function\n");
        timer_start();
        pr_info("Driver loaded!\n");
        return 0;
}
  • This function deletes pending timer and stops it’s execution.

void timer_stop(void)
{
        del_timer(&drv_var.my_timer);
}
  • This function calls timer_stop function, will be executed once the module is removed from the linux kernel.

static void __exit timer_exit(void)
{
        pr_info("Inside timer_exit function\n");
        timer_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(timer_init);
module_exit(timer_exit);
 1#include <linux/init.h>
 2#include <linux/kernel.h>
 3#include <linux/module.h>
 4#include <linux/fs.h>
 5#include <linux/timer.h>
 6#include <linux/jiffies.h>
 7#include <linux/err.h>
 8
 9#define TIMEOUT 5000 
10
11MODULE_LICENSE("GPL");
12MODULE_AUTHOR("Linux_usr");
13MODULE_DESCRIPTION("One Shot Timer");
14
15void timer_start(void);
16void timer_stop(void);
17
18struct my_drv_info {
19        struct timer_list my_timer;
20        int data_a;
21        int data_b;
22        char data_c;
23        char data_d[10];
24};
25
26struct my_drv_info drv_var;
27
28/* timer_callback - executes once the timer expires */
29static void timer_callback(struct timer_list *t)
30{
31	pr_info("Inside Timer Callback function\n");
32	 
33	struct my_drv_info *my_drv_info_ptr = from_timer(my_drv_info_ptr, t, my_timer);
34        pr_info("%s : data_a : %d\n", __func__, my_drv_info_ptr->data_a);
35        pr_info("%s : data_b : %d\n", __func__, my_drv_info_ptr->data_b);
36        pr_info("%s : data_c : %c\n", __func__, my_drv_info_ptr->data_c);
37        pr_info("%s : data_d : %s\n", __func__, my_drv_info_ptr->data_d);
38        mod_timer(&my_drv_info_ptr->my_timer, jiffies + msecs_to_jiffies(TIMEOUT));
39}
40
41/* timer_start - setup the timer to call timer_callback() using timer_setup,
42 * start a timer using add_timer
43 */
44void timer_start(void) 
45{
46	drv_var.data_a = 10;
47        drv_var.data_b = 20;
48        drv_var.data_c = 'a';
49        strncpy(drv_var.data_d, "hello", sizeof(drv_var.data_d));
50
51        timer_setup(&drv_var.my_timer, timer_callback, 0);
52        add_timer(&drv_var.my_timer);
53}
54
55/* timer_init - calls timer_start function,
56 * will be executed once the module is loaded into the linux kernel
57 */
58static int __init timer_init(void)
59{
60	pr_info("Inside timer_init function\n");
61	timer_start();
62	pr_info("Driver loaded!\n");
63	
64	return 0;
65}
66
67/* timer_stop - Deletes pending timer and stops it's execution */
68void timer_stop(void)
69{
70	del_timer(&drv_var.my_timer);
71}
72
73/* timer_exit - calls timer_stop function,
74 * will be executed once the module is removed from the linux kernel
75 */
76static void __exit timer_exit(void)
77{
78	pr_info("Inside timer_exit function\n");
79	timer_stop();
80	pr_info("Driver unloaded!\n");
81}
82
83module_init(timer_init);
84module_exit(timer_exit);
1obj-m += timer.o
2
3all:
4	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
5
6clean:
7	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/test/Desktop/kernel_api/start_timer/tc1 modules
make[1]: Entering directory '/home/test/Desktop/kernel_api/linux-6.8'
  CC [M]  /home/test/Desktop/kernel_api/start_timer/tc1/timer.o
  MODPOST /home/test/Desktop/kernel_api/start_timer/tc1/Module.symvers
  CC [M]  /home/test/Desktop/kernel_api/start_timer/tc1/timer.mod.o
  LD [M]  /home/test/Desktop/kernel_api/start_timer/tc1/timer.ko
make[1]: Leaving directory '/home/test/Desktop/kernel_api/linux-6.8'
  • Check if the .ko is generated or not using ls command.

$ ls -l
total 376
-rw-rw-r-- 1 test test    155 Jul 19 14:57 Makefile
-rw-rw-r-- 1 test test     73 Jul 19 15:03 modules.order
-rw-rw-r-- 1 test test      0 Jul 19 15:03 Module.symvers
-rw-rw-r-- 1 test test   2143 Jul 19 14:57 timer.c
-rw-rw-r-- 1 test test 178696 Jul 19 15:03 timer.ko
-rw-rw-r-- 1 test test     73 Jul 19 15:03 timer.mod
-rw-rw-r-- 1 test test   1066 Jul 19 15:03 timer.mod.c
-rw-rw-r-- 1 test test 149232 Jul 19 15:03 timer.mod.o
-rw-rw-r-- 1 test test  30880 Jul 19 15:03 timer.o
  • Run modinfo command to get the information about the kernel module.

$ modinfo timer.ko
filename:       /home/test/Desktop/kernel_api/start_timer/tc1/timer.ko
description:    Timer
author:         Linux_usr
license:        GPL
srcversion:     11588D0D1B327CC872264E3
depends:
retpoline:      Y
name:           timer
vermagic:       6.8.0 SMP preempt mod_unload modversions
  • insert the module using insmod command.

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

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

$ sudo dmesg
[257437.535046] Inside timer_init function
[257437.535054] Driver loaded!
[257437.535998] Inside Timer Callback function
[257437.536001] timer_callback : data_a : 10
[257437.536005] timer_callback : data_b : 20
[257437.536007] timer_callback : data_c : a
[257437.536009] timer_callback : data_d : hello
[257442.540044] Inside Timer Callback function
[257442.540085] timer_callback : data_a : 10
[257442.540094] timer_callback : data_b : 20
[257442.540100] timer_callback : data_c : a
[257442.540104] timer_callback : data_d : hello
  • remove the module from kernel using rmmod command.

$ sudo rmmod timer
  • 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 timer
  • Check for kernel messages from exit function using dmesg command.

$ sudo dmesg
[257452.054507] Inside timer_exit function
[257452.054517] Driver unloaded!
  • In this example let’s see how to start the timer using add_timer_on 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/timer.h>
#include <linux/jiffies.h>
#include <linux/err.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("Timer");
  • Setting up the timer which we are going to create and use in this example

timer_setup(&drv_var.my_timer, timer_callback, 0);
  • This function executes once the timer expires.

static void timer_callback(struct timer_list * t)
{
        pr_info("Inside Timer Callback function\n");

        struct my_drv_info * my_drv_info_ptr = from_timer(my_drv_info_ptr, t, my_timer);
        pr_info("%s : data_a : %d\n", __func__, my_drv_info_ptr->data_a);
        pr_info("%s : data_b : %d\n", __func__, my_drv_info_ptr->data_b);
        pr_info("%s : data_c : %c\n", __func__, my_drv_info_ptr->data_c);
        pr_info("%s : data_d : %s\n", __func__, my_drv_info_ptr->data_d);
}
  • This function setup the timer to call timer_callback() using timer_setup.

  • Starts timer using add_timer_on.

void timer_start(void)
{
        int cpu = 0;
        drv_var.data_a = 10;
        drv_var.data_b = 20;
        drv_var.data_c = 'a';
        strncpy(drv_var.data_d, "hello", sizeof(drv_var.data_d));

        timer_setup(&drv_var.my_timer, timer_callback, 0);
        add_timer_on(&drv_var.my_timer, cpu);
}
  • This function calls timer_start function, will be executed once the module is loaded into the linux kernel.

static int __init timer_init(void)
{
        pr_info("Inside timer_init function\n");
        timer_start();
        pr_info("Driver loaded!\n");
        return 0;
}
  • This function deletes pending timer and stops it’s execution.

void timer_stop(void)
{
        del_timer(&drv_var.my_timer);
}
  • This function calls timer_stop function, will be executed once the module is removed from the linux kernel.

static void __exit timer_exit(void)
{
        pr_info("Inside timer_exit function\n");
        timer_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(timer_init);
module_exit(timer_exit);
 1#include <linux/init.h>
 2#include <linux/kernel.h>
 3#include <linux/module.h>
 4#include <linux/fs.h>
 5#include <linux/timer.h>
 6#include <linux/jiffies.h>
 7#include <linux/err.h>
 8
 9#define TIMEOUT 5000 
10
11MODULE_LICENSE("GPL");
12MODULE_AUTHOR("Linux_usr");
13MODULE_DESCRIPTION("Timer");
14
15void timer_start(void);
16void timer_stop(void);
17
18struct my_drv_info {
19	struct timer_list my_timer;
20	int data_a;
21	int data_b;
22	char data_c;
23	char data_d[10];
24};
25
26struct my_drv_info drv_var;
27
28/* timer_callback - executes once the timer expires */ 
29static void timer_callback(struct timer_list *t)
30{
31	pr_info("Inside Timer Callback function\n");
32
33	struct my_drv_info *my_drv_info_ptr = from_timer(my_drv_info_ptr, t, my_timer);
34	pr_info("%s : data_a : %d\n", __func__, my_drv_info_ptr->data_a);
35	pr_info("%s : data_b : %d\n", __func__, my_drv_info_ptr->data_b);
36	pr_info("%s : data_c : %c\n", __func__, my_drv_info_ptr->data_c);
37	pr_info("%s : data_d : %s\n", __func__, my_drv_info_ptr->data_d);
38}
39
40/* timer_start - setup the timer to call the timer_callback() using timer_setup,
41 * start a timer using add_timer_on
42 */
43void timer_start(void)
44{
45	int cpu = 0;
46        drv_var.data_a = 10;
47        drv_var.data_b = 20;
48        drv_var.data_c = 'a';
49        strncpy(drv_var.data_d, "hello", sizeof(drv_var.data_d));
50
51        timer_setup(&drv_var.my_timer, timer_callback, 0);
52        add_timer_on(&drv_var.my_timer, cpu);
53}
54
55/* timer_init - calls timer_start function,
56 * will be executed once the module is loaded into the linux kernel
57 */
58static int __init timer_init(void)
59{
60	pr_info("Inside timer_init function\n");
61	timer_start();
62	pr_info("Driver loaded!\n");
63	return 0;
64}
65
66/* timer_stop - deletes pending timer and stops it's execution */
67void timer_stop(void)
68{
69	del_timer(&drv_var.my_timer);
70}
71
72/* timer_exit - calls timer_stop function,
73 * will be executed once the module is removed from the linux kernel
74 */
75static void __exit timer_exit(void)
76{
77	pr_info("Inside timer_exit function\n");
78	timer_stop();
79	pr_info("Driver unloaded!\n");
80}
81
82module_init(timer_init);
83module_exit(timer_exit);
1obj-m += timer.o
2
3all:
4	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
5
6clean:
7	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/test/Desktop/kernel_api/start_timer/tc2 modules
make[1]: Entering directory '/home/test/Desktop/kernel_api/linux-6.8'
  CC [M]  /home/test/Desktop/kernel_api/start_timer/tc2/timer.o
  MODPOST /home/test/Desktop/kernel_api/start_timer/tc2/Module.symvers
  CC [M]  /home/test/Desktop/kernel_api/start_timer/tc2/timer.mod.o
  LD [M]  /home/test/Desktop/kernel_api/start_timer/tc2/timer.ko
make[1]: Leaving directory '/home/test/Desktop/kernel_api/linux-6.8'
  • Check if the .ko is generated or not using ls command.

$ ls -l
total 376
-rw-rw-r-- 1 test test    155 Jul 19 14:57 Makefile
-rw-rw-r-- 1 test test     73 Jul 19 15:03 modules.order
-rw-rw-r-- 1 test test      0 Jul 19 15:03 Module.symvers
-rw-rw-r-- 1 test test   2143 Jul 19 14:57 timer.c
-rw-rw-r-- 1 test test 178696 Jul 19 15:03 timer.ko
-rw-rw-r-- 1 test test     73 Jul 19 15:03 timer.mod
-rw-rw-r-- 1 test test   1066 Jul 19 15:03 timer.mod.c
-rw-rw-r-- 1 test test 149232 Jul 19 15:03 timer.mod.o
-rw-rw-r-- 1 test test  30880 Jul 19 15:03 timer.o
  • Run modinfo command to get the information about the kernel module.

$ modinfo timer.ko
filename:       /home/test/Desktop/kernel_api/start_timer/tc2/timer.ko
description:    Timer
author:         Linux_usr
license:        GPL
srcversion:     11588D0D1B327CC872264E3
depends:
retpoline:      Y
name:           timer
vermagic:       6.8.0 SMP preempt mod_unload modversions
  • insert the module using insmod command.

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

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

$ sudo dmesg
[257507.421232] Inside timer_init function
[257507.421243] Driver loaded!
[257507.423480] Inside Timer Callback function
[257507.423492] timer_callback : data_a : 10
[257507.423499] timer_callback : data_b : 20
[257507.423502] timer_callback : data_c : a
[257507.423504] timer_callback : data_d : hello
  • remove the module from kernel using rmmod command.

$ sudo rmmod timer
  • 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 timer
  • Check for kernel messages from exit function using dmesg command.

$ sudo dmesg
[257549.931569] Inside timer_exit function
[257549.931573] Driver unloaded!