Workqueue : queue_delayed_work : periodic

  • In this program, you are going to learn

  • How to schedule a specific workqueue with a specified delay periodically ?

  • INIT_DELAYED_WORK is a macro to initialize a delayed workqueue. For example, For example,

INIT_DELAYED_WORK(&d_work, workqueue_func);
  • queue_delayed_work is a function used to schedule a specific workqueue with a specified delay before execution. For example,

queue_delayed_work(system_wq, &d_work, msecs_to_jiffies(TIMEOUT));
  • cancel_delayed_work_sync is a function used to cancel a previously scheduled delayed workqueue and wait for it to complete before returning. For example,

cancel_delayed_work_sync(&d_work);
static void workqueue_func(struct work_struct * work)
{
        queue_delayed_work(system_wq, &d_work, msecs_to_jiffies(TIMEOUT));
        pr_info("I am entering the workqueue function\n");
}
  • 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/workqueue.h>
#include <linux/jiffies.h>
#include <linux/delay.h>
  • Include the headers file to refer the APIs used in this program.

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux_usr");
MODULE_DESCRIPTION("Workqueue");
  • Add the modules macro which contains the information of module such as license, author and description.

void workqueue_func(struct work_struct *work);

static struct delayed_work d_work;
  • Initialize the variables and APIs which is used in this program.

static int __init queue_init(void)
{

    INIT_DELAYED_WORK(&d_work, workqueue_func);
        queue_delayed_work(system_wq, &d_work, msecs_to_jiffies(TIMEOUT));

    pr_info("Driver Loaded\n");

    return 0;
}
  • Create the module init function which will be called once the module is loaded into linux kernel.

  • schedule_work is used to schedule the workqueue.

static void __exit queue_exit(void)
{
    cancel_delayed_work_sync(&d_work);
        pr_info("Driver Unloaded...\n");
}
  • Create the module exit function which will be called once the module is unloaded into linux kernel.

void workqueue_func(struct work_struct *work)
{
    queue_delayed_work(system_wq, &d_work, msecs_to_jiffies(TIMEOUT));
    pr_info("I am entering the workqueue function\n");
}
  • Workqueue APIs is called once the work is scheduled.

  • This API will be passed as a parameter during the time of declaring the workqueue.

module_init(queue_init);
module_exit(queue_exit);
  • Mention the module init and exit functions which needs to be executed when 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/workqueue.h>
 6#include <linux/jiffies.h>
 7#include <linux/delay.h>
 8
 9#define TIMEOUT 1000
10
11MODULE_LICENSE("GPL");
12MODULE_AUTHOR("Linux_usr");
13MODULE_DESCRIPTION("Workqueue");
14
15static void workqueue_func(struct work_struct *work);
16
17static struct delayed_work d_work;
18
19static void workqueue_func(struct work_struct *work)
20{
21	queue_delayed_work(system_wq, &d_work, msecs_to_jiffies(TIMEOUT));
22	pr_info("I am entering the workqueue function\n");
23}
24
25static int __init queue_init(void)
26{
27	INIT_DELAYED_WORK(&d_work, workqueue_func);
28	queue_delayed_work(system_wq, &d_work, msecs_to_jiffies(TIMEOUT));
29
30	pr_info("Driver Loaded...\n");
31
32	return 0;
33}
34
35static void __exit queue_exit(void)
36{
37	cancel_delayed_work_sync(&d_work);
38	pr_info("Driver Unloaded...\n");
39}
40
41module_init(queue_init);
42module_exit(queue_exit);
 1obj-m += work_queue.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 load the kernel module.

$ make
make -C /lib/modules/5.4.0-150-generic/build M=$HOME/kernel_work_queue modules
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-150-generic'
  CC [M]  $HOME/kernel_work_queue/work_queue.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC [M]  $HOME/kernel_work_queue/work_queue.mod.o
  LD [M]  $HOME/kernel_work_queue/work_queue.ko
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-150-generic'
  • Check if work_queue.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 work_queue.c
-rw-rw-r-- 1 test test 5880 Feb 26 13:18 work_queue.ko
-rw-rw-r-- 1 test test   47 Feb 26 13:18 work_queue.mod
-rw-rw-r-- 1 test test  919 Feb 26 13:18 work_queue.mod.c
-rw-rw-r-- 1 test test 3448 Feb 26 13:18 work_queue.mod.o
-rw-rw-r-- 1 test test 3320 Feb 26 13:18 work_queue.o
  • Load the module to kernel using insmod command.

$ sudo insmod ./work_queue.ko
  • Check kernel messages to verify if the module is loaded or not.

$ dmesg
[80566.951801] Driver Loaded...
[80567.958063] I am entering the workqueue function
[80568.982072] I am entering the workqueue function
[80570.006074] I am entering the workqueue function
[80571.030109] I am entering the workqueue function
[80572.054129] I am entering the workqueue function
[80573.078089] I am entering the workqueue function
[80574.102170] I am entering the workqueue function
[80575.126170] I am entering the workqueue function
[80576.150186] I am entering the workqueue function
[80577.174174] I am entering the workqueue function
[80578.198172] I am entering the workqueue function
[80579.222235] I am entering the workqueue function
[80580.246211] I am entering the workqueue function
[80581.270253] I am entering the workqueue function
  • Unload the module using rmmod command.

$ sudo rmmod work_queue
  • Check kernel messages to see if the module is unloaded or not.

$ dmesg
[80566.951801] Driver Loaded...
[80567.958063] I am entering the workqueue function
[80568.982072] I am entering the workqueue function
[80570.006074] I am entering the workqueue function
[80571.030109] I am entering the workqueue function
[80572.054129] I am entering the workqueue function
[80573.078089] I am entering the workqueue function
[80574.102170] I am entering the workqueue function
[80575.126170] I am entering the workqueue function
[80576.150186] I am entering the workqueue function
[80577.174174] I am entering the workqueue function
[80578.198172] I am entering the workqueue function
[80579.222235] I am entering the workqueue function
[80580.246211] I am entering the workqueue function
[80581.270253] I am entering the workqueue function
[80581.568098] Driver Unloaded...

API

Learning

INIT_DELAYED_WORK

To initialize a delayed workqueue

queue_delayed_work

To schedule a specific workqueue with a specified delay

msecs_to_jiffies

To convert milliseconds

cancel_delayed_work_sync

To cancel a previously scheduled delayed workqueue