Create Static Work

#

Version

Ubuntu

Ubuntu 22.10

Kernel

6.8.0

  • In this program, you are going to learn

  • How to create workqueue ?

  • How to allocate the work to the queue ?

#include <linux/workqueue.h>

#define DECLARE_WORK(n, f)
  • Here is an example of how to use the API,

static DECLARE_WORK(my_work_1,workqueue_func_1);
  • Here is the function prototype of the API: work_busy

#include <linux/workqueue.h>

extern unsigned int work_busy(struct work_struct *work);
  • Here is an example of how to use the API,

work_busy(&my_work_1);
#include <linux/workqueue.h>

static inline bool schedule_work(struct work_struct *work);
  • Here is an example of how to use the API,

schedule_work(&my_work_1);
#include <linux/workqueue.h>

#define DECLARE_DEFERRABLE_WORK(n, f)
  • Here is an example of how to use the API,

static DECLARE_DELAYED_WORK(my_work_1,workqueue_func_1);
#include <linux/workqueue.h>

static inline bool schedule_delayed_work(struct delayed_work *dwork, unsigned long delay);
  • Here is an example of how to use the API,

schedule_delayed_work(&my_work_1,msecs_to_jiffies(100));
#include <linux/workqueue.h>

extern bool cancel_delayed_work_sync(struct delayed_work *dwork);
  • Here is an example of how to use the API,

cancel_delayed_work_sync(&my_work_1);
  • In this example let’s see how to create workqueue 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/workqueue.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
  • Add the following module macros to display information about the license, author and description about the module.

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux_usr");
MODULE_DESCRIPTION("Example of DECLARE_WORK");
  • Declare and Initialize the work which we are going to use in this example

static DECLARE_WORK(my_work_1,workqueue_func_1);
static DECLARE_WORK(my_work_2,workqueue_func_2);
  • This workqueue_func_1 function executes when work is queued to workqueue.

void workqueue_func_1(struct work_struct *work)
{
    int i = 0;
    while (i < 10) {
        pr_info("Inside workqueue_func_1\n");
        i++;
        msleep(500);
    }
}
  • This workqueue_func_2 function executes when work is queued to workqueue.

void workqueue_func_2(struct work_struct * work)
{
    int i = 0;
    while (i < 10) {
        pr_info("Inside workqueue_func_2\n");
        i++;
        msleep(500);
    }
}
  • This function executes during execution of queue_start, creates workqueue, intiializes work and queues to the workqueue.

void queue_start(void)
{
    static DECLARE_WORK(my_work_1,workqueue_func_1);
    static DECLARE_WORK(my_work_2,workqueue_func_2);
    if (!work_busy(&my_work_1))
        schedule_work(&my_work_1);
    if (!work_busy(&my_work_2))
        schedule_work(&my_work_2);
}
  • This function executes when module is loaded.

static int __init queue_init(void)
{
        pr_info("Inside queue_init function\n");
        queue_start();
        return 0;
}
  • This function executes during execution of queue_exit, waits until the completion and destroys workqueue.

void queue_stop(void)
{
        pr_info("Destroying workqueue\n");
}
  • This function executes when module is unloaded.

static void __exit queue_exit(void)
{
        pr_info("Inside queue_exit function\n");
        queue_stop();
        return;
}
  • Add the driver entry points which will be executed once the module is inserted or removed from the kernel.

module_init(queue_init);
module_exit(queue_exit);
 1#include <linux/init.h>
 2#include <linux/kernel.h>
 3#include <linux/module.h>
 4#include <linux/workqueue.h>
 5#include <linux/delay.h>
 6#include <linux/jiffies.h>
 7
 8#define WQ_NAME "tc_workqueue"
 9
10MODULE_LICENSE("GPL");
11MODULE_AUTHOR("Linux_usr");
12MODULE_DESCRIPTION("Example of DECLARE_WORK");
13
14
15void workqueue_func_1(struct work_struct *work);
16void workqueue_func_2(struct work_struct *work);
17void queue_start(void);
18void queue_stop(void);
19
20/* workqueue_func_1 - executes when work is queued to workqueue,
21 * prints a statement and sleeps for 1000ms,
22 * stops when i value is greater than 10 */
23
24void workqueue_func_1(struct work_struct *work)
25{
26    int i = 0;
27    while (i < 10) {
28        pr_info("Inside workqueue_func_1\n");
29        i++;
30        msleep(500);
31    }
32}
33
34/* workqueue_func_2 - executes when work is queued to workqueue,
35 * prints a statement and sleeps for 1000ms,
36 * stops when i value is greater than 10 */
37
38void workqueue_func_2(struct work_struct *work)
39{
40    int i = 0;
41    while (i < 10) {
42        pr_info("Inside workqueue_func_2\n");
43        i++;
44        msleep(500);
45    }
46}
47
48/* queue_start - executes during execution of queue_start,
49 * creates workqueue,
50 * intiializes work and queues to the workqueue */
51
52void queue_start(void)
53{
54    static DECLARE_WORK(my_work_1,workqueue_func_1);
55    static DECLARE_WORK(my_work_2,workqueue_func_2);
56    if (!work_busy(&my_work_1))
57        schedule_work(&my_work_1);
58    if (!work_busy(&my_work_2))
59        schedule_work(&my_work_2);
60}
61
62/* queue_init - executes when module is loaded,
63 * calls queue_start */
64
65static int __init queue_init(void)
66{
67    pr_info("Inside queue_init function\n");
68    queue_start();
69    return 0;
70}
71
72/* queue_stop - executes during execution of queue_exit,
73 * waits until the completion and destroys workqueue */
74
75void queue_stop(void)
76{
77    pr_info("Destroying workqueue\n");
78}
79
80/* queue_exit - executes when module is unloaded,
81 * calls queue_stop */
82
83static void __exit queue_exit(void)
84{
85    pr_info("Inside queue_exit function\n");
86    queue_stop();
87    return;
88}
89
90module_init(queue_init);
91module_exit(queue_exit);
1obj-m += tc1.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 load the kernel module.

$ make
  • Check if work_queue.ko is generated or not using ls command.

$ ls -l
total 376
-rw-rw-r-- 1 test test    151 Aug  2 11:44 Makefile
-rw-rw-r-- 1 test test     78 Aug  2 12:35 modules.order
-rw-rw-r-- 1 test test      0 Aug  2 12:35 Module.symvers
-rw-rw-r-- 1 test test   2108 Aug  2 11:44 tc1.c
-rw-rw-r-- 1 test test 179016 Aug  2 12:35 tc1.ko
-rw-rw-r-- 1 test test     78 Aug  2 12:35 tc1.mod
-rw-rw-r-- 1 test test   1088 Aug  2 12:35 tc1.mod.c
-rw-rw-r-- 1 test test 149280 Aug  2 12:35 tc1.mod.o
-rw-rw-r-- 1 test test  31192 Aug  2 12:35 tc1.o
  • Load the module to kernel using insmod command.

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

$ dmesg
[ 1002.253754] Inside queue_init function
[ 1002.254259] Inside workqueue_func_1
[ 1002.254796] Inside workqueue_func_2
[ 1002.778660] Inside workqueue_func_2
[ 1002.778688] Inside workqueue_func_1
[ 1003.290690] Inside workqueue_func_1
[ 1003.290706] Inside workqueue_func_2
[ 1003.802673] Inside workqueue_func_1
[ 1003.802700] Inside workqueue_func_2
[ 1004.314534] Inside workqueue_func_2
[ 1004.314554] Inside workqueue_func_1
[ 1004.826694] Inside workqueue_func_1
[ 1004.826711] Inside workqueue_func_2
[ 1005.338667] Inside workqueue_func_2
[ 1005.338685] Inside workqueue_func_1
[ 1005.850679] Inside workqueue_func_1
[ 1005.850696] Inside workqueue_func_2
[ 1006.362675] Inside workqueue_func_2
[ 1006.362692] Inside workqueue_func_1
[ 1006.874679] Inside workqueue_func_1
[ 1006.874695] Inside workqueue_func_2
  • Unload the module using rmmod command.

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

$ dmesg
[ 1020.585671] Inside queue_exit function
[ 1020.585677] Destroying workqueue
  • In this example let’s see how to Create and initialize the workqueue workqueue 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/workqueue.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
  • Add the following module macros to display information about the license, author and description about the module.

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux_usr");
MODULE_DESCRIPTION("Example of DECLARE_DELAYED_WORK");
  • Declare and Initialize the work which we are going to use in this example

static DECLARE_DELAYED_WORK(my_work_1,workqueue_func_1);
static DECLARE_DELAYED_WORK(my_work_2,workqueue_func_2);
  • This workqueue_func_1 function executes when work is queued to workqueue.

void workqueue_func_1(struct work_struct *work)
{
    int i = 0;
    while (i < 10) {
        pr_info("Inside workqueue_func_1\n");
        i++;
        msleep(500);
    }
}
  • This workqueue_func_2 function executes when work is queued to workqueue.

void workqueue_func_2(struct work_struct * work)
{
    int i = 0;
    while (i < 10) {
        pr_info("Inside workqueue_func_2\n");
        i++;
        msleep(500);
    }
}
  • This function executes during execution of queue_start, creates workqueue, intiializes work and queues to the workqueue.

void queue_start(void)
{
        schedule_delayed_work(&my_work_1,msecs_to_jiffies(100));
        schedule_delayed_work(&my_work_2,msecs_to_jiffies(50));
}
  • This function executes when module is loaded.

static int __init queue_init(void)
{
        pr_info("Inside queue_init function\n");
        queue_start();
        return 0;
}
  • This function executes during execution of queue_exit, waits until the completion and destroys workqueue.

void queue_stop(void)
{
        pr_info("Destroying workqueue\n");
        cancel_delayed_work_sync(&my_work_1);
        cancel_delayed_work_sync(&my_work_2);
}
  • This function executes when module is unloaded.

static void __exit queue_exit(void)
{
        pr_info("Inside queue_exit function\n");
        queue_stop();
        return;
}
  • Add the driver entry points which will be executed once the module is inserted or removed from the kernel.

module_init(queue_init);
module_exit(queue_exit);
 1#include <linux/init.h>
 2#include <linux/kernel.h>
 3#include <linux/module.h>
 4#include <linux/workqueue.h>
 5#include <linux/delay.h>
 6#include <linux/jiffies.h>
 7
 8MODULE_LICENSE("GPL");
 9MODULE_AUTHOR("Linux_usr");
10MODULE_DESCRIPTION("Example of DECLARE_DELAYED_WORK");
11
12void workqueue_func_1(struct work_struct *work);
13void workqueue_func_2(struct work_struct *work);
14void queue_start(void);
15void queue_stop(void);
16static DECLARE_DELAYED_WORK(my_work_1,workqueue_func_1);
17static DECLARE_DELAYED_WORK(my_work_2,workqueue_func_2);
18
19/* workqueue_func_1 - executes when work is queued to workqueue,
20 * prints a statement and sleeps for 1000ms,
21 * stops when i value is greater than 10 */
22
23void workqueue_func_1(struct work_struct *work)
24{
25    int i = 0;
26    while (i < 10) {
27        pr_info("Inside workqueue_func_1\n");
28        i++;
29        msleep(500);
30    }
31}
32
33/* workqueue_func_2 - executes when work is queued to workqueue,
34 * prints a statement and sleeps for 1000ms,
35 * stops when i value is greater than 10 */
36
37void workqueue_func_2(struct work_struct *work)
38{
39    int i = 0;
40    while (i < 10) {
41        pr_info("Inside workqueue_func_2\n");
42        i++;
43        msleep(500);
44    }
45}
46
47/* queue_start - executes during execution of queue_start,
48 * creates workqueue,
49 * intiializes work and queues to the workqueue */
50
51void queue_start(void)
52{
53    schedule_delayed_work(&my_work_1,msecs_to_jiffies(100));
54    schedule_delayed_work(&my_work_2,msecs_to_jiffies(50));
55}
56
57/* queue_init - executes when module is loaded,
58 * calls queue_start */
59
60static int __init queue_init(void)
61{
62    pr_info("Inside queue_init function\n");
63    queue_start();
64    return 0;
65}
66
67/* queue_stop - executes during execution of queue_exit,
68 * waits until the completion and destroys workqueue */
69
70void queue_stop(void)
71{
72    pr_info("Destroying workqueue\n");
73    cancel_delayed_work_sync(&my_work_1);
74    cancel_delayed_work_sync(&my_work_2);
75}
76
77/* queue_exit - executes when module is unloaded,
78 * calls queue_stop */
79
80static void __exit queue_exit(void)
81{
82    pr_info("Inside queue_exit function\n");
83    queue_stop();
84    return;
85}
86
87module_init(queue_init);
88module_exit(queue_exit);
1obj-m += tc2.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 load the kernel module.

$ make
  • Check if work_queue.ko is generated or not using ls command.

$ ls -l
total 384
-rw-rw-r-- 1 test test    151 Aug  2 11:44 Makefile
-rw-rw-r-- 1 test test     86 Aug  2 12:37 modules.order
-rw-rw-r-- 1 test test      0 Aug  2 12:37 Module.symvers
-rw-rw-r-- 1 test test   2162 Aug  2 11:44 tc2.c
-rw-rw-r-- 1 test test 183096 Aug  2 12:37 tc2.ko
-rw-rw-r-- 1 test test     86 Aug  2 12:37 tc2.mod
-rw-rw-r-- 1 test test   1154 Aug  2 12:37 tc2.mod.c
-rw-rw-r-- 1 test test 149360 Aug  2 12:37 tc2.mod.o
-rw-rw-r-- 1 test test  35232 Aug  2 12:37 tc2.o
  • Load the module to kernel using insmod command.

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

$ dmesg
[ 1103.744537] Inside queue_init function
[ 1103.802566] Inside workqueue_func_2
[ 1103.846670] Inside workqueue_func_1
[ 1104.318668] Inside workqueue_func_2
[ 1104.382460] Inside workqueue_func_1
[ 1104.826648] Inside workqueue_func_2
[ 1104.890626] Inside workqueue_func_1
[ 1105.338669] Inside workqueue_func_2
[ 1105.402457] Inside workqueue_func_1
[ 1105.850645] Inside workqueue_func_2
[ 1105.914622] Inside workqueue_func_1
[ 1106.362673] Inside workqueue_func_2
[ 1106.426647] Inside workqueue_func_1
[ 1106.874644] Inside workqueue_func_2
[ 1106.938592] Inside workqueue_func_1
[ 1107.386669] Inside workqueue_func_2
[ 1107.450623] Inside workqueue_func_1
[ 1107.898637] Inside workqueue_func_2
[ 1107.962624] Inside workqueue_func_1
[ 1108.410666] Inside workqueue_func_2
[ 1108.474643] Inside workqueue_func_1
  • Unload the module using rmmod command.

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

$ dmesg
[ 1117.920445] Inside queue_exit function
[ 1117.920449] Destroying workqueue