Destroy 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 create_workqueue(name)
  • Here is an example of how to use the API,

my_workqueue = create_workqueue(WQ_NAME);
  • Here is the function prototype of the API: INIT_WORK

#include <linux/workqueue.h>

#define INIT_WORK(_work, _func)
  • Here is an example of how to use the API,

INIT_WORK(&my_work_1,workqueue_func_1);
  • Here is the function prototype of the API: queue_work

#include <linux/workqueue.h>

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

queue_work(my_workqueue,&my_work_1);
  • Here is the function prototype of the API: queue_work

#include <linux/workqueue.h>

extern void destroy_workqueue(struct workqueue_struct *wq);
  • Here is an example of how to use the API,

destroy_workqueue(my_workqueue);
#include <linux/workqueue.h>

#define work_pending(work)
  • Here is an example of how to use the API,

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

#define INIT_DELAYED_WORK(_work, _func)
  • Here is an example of how to use the API,

INIT_DELAYED_WORK(&my_work_1,workqueue_func_1);
INIT_DELAYED_WORK(&my_work_2,workqueue_func_2);
#include <linux/workqueue.h>

#define delayed_work_pending(w)
  • Here is an example of how to use the API,

delayed_work_pending(&my_work_1);
#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);
cancel_delayed_work_sync(&my_work_2);
#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);
schedule_work(&my_work_2);
  • Here is the function prototype of the API: cancel_work

#include <linux/workqueue.h>

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

cancel_work(&my_work_1);
cancel_work(&my_work_2);
#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,msecs_to_jiffies(100));
#include <linux/workqueue.h>

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

cancel_delayed_work(&my_work);
  • In this example let’s see how to destroy the 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 cancel_workqueue");
  • Initialize the work which we are going to use in this example

INIT_WORK(&my_work_1,workqueue_func_1);
INIT_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(1000);
        }
}
  • 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_1\n");
                i++;
                msleep(1000);
        }
}
  • This function creates workqueue, intiializes work and queues to the workqueue.

void queue_start(void)
{
    my_workqueue = create_workqueue(WQ_NAME);
    INIT_WORK(&my_work_1,workqueue_func_1);
    INIT_WORK(&my_work_2,workqueue_func_2);
    if (!work_pending(&my_work_1)) {
        queue_work(my_workqueue,&my_work_1);
    }
    if (!work_pending(&my_work_2)) {
        queue_work(my_workqueue,&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");
        cancel_work(&my_work_1);
        cancel_work(&my_work_2);
        destroy_workqueue(my_workqueue);
}
  • 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/* schedule_work/delayed_work_pending */
  2
  3#include <linux/init.h>
  4#include <linux/kernel.h>
  5#include <linux/module.h>
  6#include <linux/workqueue.h>
  7#include <linux/delay.h>
  8#include <linux/jiffies.h>
  9
 10#define WQ_NAME "tc8_workqueue"
 11
 12MODULE_LICENSE("GPL");
 13MODULE_AUTHOR("Linux_usr");
 14MODULE_DESCRIPTION("Example of work_pending");
 15
 16struct workqueue_struct *my_workqueue;
 17struct work_struct my_work_1;
 18struct work_struct my_work_2;
 19void workqueue_func_1(struct work_struct *work);
 20void workqueue_func_2(struct work_struct *work);
 21void queue_start(void);
 22void queue_stop(void);
 23
 24/* workqueue_func_1 - executes when work is queued to workqueue,
 25 * prints a statement and sleeps for 1000ms,
 26 * stops when i value is greater than 10 */
 27
 28void workqueue_func_1(struct work_struct *work)
 29{
 30    int i = 0;
 31    while (i < 10) {
 32        pr_info("Inside workqueue_func_1\n");
 33        i++;
 34        msleep(500);
 35    }
 36}
 37
 38/* workqueue_func_2 - executes when work is queued to workqueue,
 39 * prints a statement and sleeps for 1000ms,
 40 * stops when i value is greater than 10 */
 41
 42void workqueue_func_2(struct work_struct *work)
 43{
 44    int i = 0;
 45    while (i < 10) {
 46        pr_info("Inside workqueue_func_2\n");
 47        i++;
 48        msleep(500);
 49    }
 50}
 51
 52/* queue_start - executes during execution of queue_start,
 53 * creates workqueue,
 54 * intiializes work and queues to the workqueue */
 55
 56void queue_start(void)
 57{
 58    my_workqueue = create_workqueue(WQ_NAME);
 59    INIT_WORK(&my_work_1,workqueue_func_1);
 60    INIT_WORK(&my_work_2,workqueue_func_2);
 61    if (!work_pending(&my_work_1)) {
 62        queue_work(my_workqueue,&my_work_1);
 63    }
 64    if (!work_pending(&my_work_2)) {
 65        queue_work(my_workqueue,&my_work_2);
 66    }
 67}
 68
 69/* queue_init - executes when module is loaded,
 70 * calls queue_start */
 71
 72static int __init queue_init(void)
 73{
 74    pr_info("Inside queue_init function\n");
 75    queue_start();
 76    return 0;
 77}
 78
 79/* queue_stop - executes during execution of queue_exit,
 80 * waits until the completion and destroys workqueue */
 81
 82void queue_stop(void)
 83{
 84    pr_info("Destroying workqueue\n");
 85    cancel_work(&my_work_1);
 86    cancel_work(&my_work_2);
 87    destroy_workqueue(my_workqueue);
 88}
 89
 90/* queue_exit - executes when module is unloaded,
 91 * calls queue_stop */
 92
 93static void __exit queue_exit(void)
 94{
 95    pr_info("Inside queue_exit function\n");
 96    queue_stop();
 97    return;
 98}
 99
100module_init(queue_init);
101module_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 384
-rw-rw-r-- 1 test test    151 Aug  2 11:47 Makefile
-rw-rw-r-- 1 test test     76 Aug  2 12:48 modules.order
-rw-rw-r-- 1 test test      0 Aug  2 12:48 Module.symvers
-rw-rw-r-- 1 test test   2040 Aug  2 11:47 tc1.c
-rw-rw-r-- 1 test test 180944 Aug  2 12:48 tc1.ko
-rw-rw-r-- 1 test test     76 Aug  2 12:48 tc1.mod
-rw-rw-r-- 1 test test   1103 Aug  2 12:48 tc1.mod.c
-rw-rw-r-- 1 test test 149280 Aug  2 12:48 tc1.mod.o
-rw-rw-r-- 1 test test  33112 Aug  2 12:48 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
[ 1812.726131] Inside queue_init function
[ 1812.726612] Inside workqueue_func_2
[ 1812.726979] Inside workqueue_func_1
[ 1813.754717] Inside workqueue_func_1
[ 1814.778711] Inside workqueue_func_1
[ 1815.802723] Inside workqueue_func_1
[ 1816.826704] Inside workqueue_func_1
[ 1817.850705] Inside workqueue_func_1
[ 1818.874707] Inside workqueue_func_1
[ 1819.898722] Inside workqueue_func_1
[ 1820.922729] Inside workqueue_func_1
[ 1821.946714] Inside workqueue_func_1
  • Unload the module using rmmod command.

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

$ dmesg
[ 1835.094347] Inside queue_exit function
  • In this example let’s see how to destroy the 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 flush_work");
  • Initialize the work which we are going to use in this example

INIT_WORK(&my_work_1,workqueue_func_1);
INIT_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(1000);
        }
}
  • 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_1\n");
                i++;
                msleep(1000);
        }
}
  • This function creates workqueue, intiializes work and queues to the workqueue.

void queue_start(void)
{
    my_workqueue = create_workqueue(WQ_NAME);
    INIT_WORK(&my_work_1,workqueue_func_1);
    INIT_WORK(&my_work_2,workqueue_func_2);
    if (!work_pending(&my_work_1)) {
        queue_work(my_workqueue,&my_work_1);
    }
    if (!work_pending(&my_work_2)) {
        queue_work(my_workqueue,&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");
        flush_work(&my_work_1);
        flush_work(&my_work_2);
        destroy_workqueue(my_workqueue);
}
  • 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 "tc8_workqueue"
 9
10MODULE_LICENSE("GPL");
11MODULE_AUTHOR("Linux_usr");
12MODULE_DESCRIPTION("Example of work_pending");
13
14struct workqueue_struct *my_workqueue;
15struct work_struct my_work_1;
16struct work_struct my_work_2;
17void workqueue_func_1(struct work_struct *work);
18void workqueue_func_2(struct work_struct *work);
19void queue_start(void);
20void queue_stop(void);
21
22/* workqueue_func_1 - executes when work is queued to workqueue,
23 * prints a statement and sleeps for 1000ms,
24 * stops when i value is greater than 10 */
25
26void workqueue_func_1(struct work_struct *work)
27{
28    int i = 0;
29    while (i < 10) {
30        pr_info("Inside workqueue_func_1\n");
31        i++;
32        msleep(500);
33    }
34}
35
36/* workqueue_func_2 - executes when work is queued to workqueue,
37 * prints a statement and sleeps for 1000ms,
38 * stops when i value is greater than 10 */
39
40void workqueue_func_2(struct work_struct *work)
41{
42    int i = 0;
43    while (i < 10) {
44        pr_info("Inside workqueue_func_2\n");
45        i++;
46        msleep(500);
47    }
48}
49
50/* queue_start - executes during execution of queue_start,
51 * creates workqueue,
52 * intiializes work and queues to the workqueue */
53
54void queue_start(void)
55{
56    my_workqueue = create_workqueue(WQ_NAME);
57    INIT_WORK(&my_work_1,workqueue_func_1);
58    INIT_WORK(&my_work_2,workqueue_func_2);
59    if (!work_pending(&my_work_1)) {
60        queue_work(my_workqueue,&my_work_1);
61    }
62    if (!work_pending(&my_work_2)) {
63        queue_work(my_workqueue,&my_work_2);
64    }
65}
66
67/* queue_init - executes when module is loaded,
68 * calls queue_start */
69
70static int __init queue_init(void)
71{
72    pr_info("Inside queue_init function\n");
73    queue_start();
74    return 0;
75}
76
77/* queue_stop - executes during execution of queue_exit,
78 * waits until the completion and destroys workqueue */
79
80void queue_stop(void)
81{
82    pr_info("Destroying workqueue\n");
83    flush_work(&my_work_1);
84    flush_work(&my_work_2);
85    destroy_workqueue(my_workqueue);
86}
87
88/* queue_exit - executes when module is unloaded,
89 * calls queue_stop */
90
91static void __exit queue_exit(void)
92{
93    pr_info("Inside queue_exit function\n");
94    queue_stop();
95    return;
96}
97
98module_init(queue_init);
99module_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:47 Makefile
-rw-rw-r-- 1 test test     76 Aug  2 12:48 modules.order
-rw-rw-r-- 1 test test      0 Aug  2 12:48 Module.symvers
-rw-rw-r-- 1 test test   2040 Aug  2 11:47 tc2.c
-rw-rw-r-- 1 test test 180944 Aug  2 12:48 tc2.ko
-rw-rw-r-- 1 test test     76 Aug  2 12:48 tc2.mod
-rw-rw-r-- 1 test test   1103 Aug  2 12:48 tc2.mod.c
-rw-rw-r-- 1 test test 149280 Aug  2 12:48 tc2.mod.o
-rw-rw-r-- 1 test test  33112 Aug  2 12:48 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
[ 1812.726131] Inside queue_init function
[ 1812.726612] Inside workqueue_func_2
[ 1812.726979] Inside workqueue_func_1
[ 1813.754717] Inside workqueue_func_1
[ 1814.778711] Inside workqueue_func_1
[ 1815.802723] Inside workqueue_func_1
[ 1816.826704] Inside workqueue_func_1
[ 1817.850705] Inside workqueue_func_1
[ 1818.874707] Inside workqueue_func_1
[ 1819.898722] Inside workqueue_func_1
[ 1820.922729] Inside workqueue_func_1
[ 1821.946714] 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
[ 1835.094347] Inside queue_exit function
  • In this example let’s see how to destroy 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 flush_delayed_work");
  • Initialize the work which we are going to use in this example

INIT_DELAYED_WORK(&my_work_1,workqueue_func_1);
INIT_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(1000);
        }
}
  • 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(1000);
        }
}
  • This function creates workqueue, intiializes work and queues to the workqueue.

void queue_start(void)
{
        my_workqueue = create_workqueue(WQ_NAME);
        INIT_DELAYED_WORK(&my_work_1,workqueue_func_1);
        INIT_DELAYED_WORK(&my_work_2,workqueue_func_2);
        queue_delayed_work(my_workqueue,&my_work_1,msecs_to_jiffies(100));
        queue_delayed_work(my_workqueue,&my_work_2,msecs_to_jiffies(300));
}
  • 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)
{
        flush_delayed_work_sync(&my_work_1);
        flush_delayed_work_sync(&my_work_2);
        pr_info("Destroying workqueue\n");
        destroy_workqueue(my_workqueue);
}
  • 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/* create_dynamic_work/INIT_DELAYED_WORK */
 2
 3#include <linux/init.h>
 4#include <linux/kernel.h>
 5#include <linux/module.h>
 6#include <linux/workqueue.h>
 7#include <linux/delay.h>
 8#include <linux/jiffies.h>
 9
10#define WQ_NAME "tc3_workqueue"
11
12MODULE_LICENSE("GPL");
13MODULE_AUTHOR("Linux_usr");
14MODULE_DESCRIPTION("Example of INIT_DELAYED_WORK");
15
16struct workqueue_struct *my_workqueue;
17struct delayed_work my_work_1;
18struct delayed_work my_work_2;
19void workqueue_func_1(struct work_struct *work);
20void workqueue_func_2(struct work_struct *work);
21void queue_start(void);
22void queue_stop(void);
23
24/* workqueue_func_1 - exectues when work_1 is queued to workqueue,
25 * prints a statement and sleeps for 1000ms,
26 * stops when i value goes greater than 10 */
27
28void workqueue_func_1(struct work_struct *work)
29{
30    int i = 0;
31    while (i < 10) {
32        pr_info("Inside workqueue_func_1\n");
33        i++;
34        msleep(1000);
35    }
36}
37
38/* workqueue_func_2 - executes when work_2 is queued to workqueue,
39 * prints a statement and sleeps for 1000ms,
40 * stops when i value goes greater than 10ms */
41
42void workqueue_func_2(struct work_struct *work)
43{
44    int i = 0;
45    while (i < 10) {
46        pr_info("Inside workqueue_func_2\n");
47        i++;
48        msleep(1000);
49    }
50}
51
52/* queue_start - executes during execution of queue_init,
53 * creates workqueue,
54 * initializes work and queues to the workqueue */
55
56void queue_start(void)
57{
58    my_workqueue = create_workqueue(WQ_NAME);
59    INIT_DELAYED_WORK(&my_work_1,workqueue_func_1);
60    INIT_DELAYED_WORK(&my_work_2,workqueue_func_2);
61    queue_delayed_work(my_workqueue,&my_work_1,msecs_to_jiffies(100));
62    queue_delayed_work(my_workqueue,&my_work_2,msecs_to_jiffies(300));
63}
64
65/* queue_init - executes when the module is inserted,
66 * calls queue_start */
67
68static int __init queue_init(void)
69{
70    pr_info("Inside queue_init function\n");
71    queue_start();
72    return 0;
73}
74
75/* queue_stop - executes during the execution of queue_exit,
76 * destroys work and workqueues */
77
78void queue_stop(void)
79{
80    flush_delayed_work(&my_work_1);
81    flush_delayed_work(&my_work_2);
82    pr_info("Destroying workqueue\n");
83    destroy_workqueue(my_workqueue);
84}
85
86/* queue_exit - executes when the module is removed,
87 * calls queue_stop */
88
89static void __exit queue_exit(void)
90{
91    pr_info("Inside queue_exit function\n");
92    queue_stop();
93    return;
94}
95
96module_init(queue_init);
97module_exit(queue_exit);
1obj-m += tc3.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 388
-rw-rw-r-- 1 test test    151 Aug  2 11:47 Makefile
-rw-rw-r-- 1 test test     84 Aug  2 12:42 modules.order
-rw-rw-r-- 1 test test      0 Aug  2 12:42 Module.symvers
-rw-rw-r-- 1 test test   2390 Aug  2 11:47 tc3.c
-rw-rw-r-- 1 test test 184616 Aug  2 12:42 tc3.ko
-rw-rw-r-- 1 test test     84 Aug  2 12:42 tc3.mod
-rw-rw-r-- 1 test test   1233 Aug  2 12:42 tc3.mod.c
-rw-rw-r-- 1 test test 149488 Aug  2 12:42 tc3.mod.o
-rw-rw-r-- 1 test test  36616 Aug  2 12:42 tc3.o
  • Load the module to kernel using insmod command.

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

$ dmesg
[282169.096177] Inside queue_init function
[282169.198261] Inside workqueue_func_1
[282170.218283] Inside workqueue_func_1
[282171.242140] Inside workqueue_func_1
[282172.266278] Inside workqueue_func_1
[282173.290254] Inside workqueue_func_1
[282174.314224] Inside workqueue_func_1
[282175.338284] Inside workqueue_func_1
[282176.362292] Inside workqueue_func_1
[282177.386297] Inside workqueue_func_1
[282178.410281] Inside workqueue_func_1
[282179.434217] Inside workqueue_func_2
[282180.458275] Inside workqueue_func_2
[282181.482260] Inside workqueue_func_2
[282182.506300] Inside workqueue_func_2
[282183.530275] Inside workqueue_func_2
[282184.554217] Inside workqueue_func_2
[282185.578258] Inside workqueue_func_2
[282186.602256] Inside workqueue_func_2
[282187.626266] Inside workqueue_func_2
[282188.650265] Inside workqueue_func_2
  • Unload the module using rmmod command.

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

$ dmesg
[282192.532346] Inside queue_exit function
[282192.532350] Destroying workqueue
  • 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 flush_rcu_work");
  • Initialize the work which we are going to use in this example

INIT_RCU_WORK(&my_work,workqueue_func);
  • This 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(1000);
        }
}
  • This function creates workqueue, intiializes work and queues to the workqueue.

void queue_start(void)
{
        my_workqueue = create_workqueue(WQ_NAME);
        INIT_RCU_WORK(&my_work,workqueue_func);
        queue_rcu_work(my_workqueue,&my_work);
}
  • 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");
        flush_rcu_work(&my_work);
        flush_workqueue(my_workqueue);
}
  • 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/* create_dynamic_work/INIT_RCU_WORK */
 2
 3#include <linux/init.h>
 4#include <linux/kernel.h>
 5#include <linux/module.h>
 6#include <linux/workqueue.h>
 7#include <linux/delay.h>
 8#include <linux/jiffies.h>
 9
10#define WQ_NAME "tc6_workqueue"
11
12MODULE_LICENSE("GPL");
13MODULE_AUTHOR("Linux_usr");
14MODULE_DESCRIPTION("Example of INIT_RCU_WORK");
15
16struct workqueue_struct *my_workqueue;
17struct rcu_work my_work;
18void workqueue_func(struct work_struct *work);
19void queue_start(void);
20void queue_stop(void);
21
22/* workqueue_func - executes when work is queued to workqueue,
23 * prints a statement and sleeps for 1000ms,
24 * stops when i value is greater than 10 */
25
26void workqueue_func(struct work_struct *work)
27{
28    int i = 0;
29    while (i < 10) {
30        pr_info("Inside workqueue_func\n");
31        i++;
32        msleep(1000);
33    }
34}
35
36/* queue_start - executes during execution of queue_start,
37 * creates workqueue,
38 * intiializes work and queues to the workqueue */
39
40void queue_start(void)
41{
42    my_workqueue = create_workqueue(WQ_NAME);
43    INIT_RCU_WORK(&my_work,workqueue_func);
44    queue_rcu_work(my_workqueue,&my_work);
45}
46
47/* queue_init - executes when module is loaded,
48 * calls queue_start */
49
50static int __init queue_init(void)
51{
52    pr_info("Inside queue_init function\n");
53    queue_start();
54    return 0;
55}
56
57/* queue_stop - executes during execution of queue_exit,
58 * waits until the completion and destroys workqueue */
59
60void queue_stop(void)
61{
62    pr_info("Destroying workqueue\n");
63    flush_rcu_work(&my_work);
64    flush_workqueue(my_workqueue);
65}
66
67/* queue_exit - executes when module is unloaded,
68 * calls queue_stop */
69
70static void __exit queue_exit(void)
71{
72    pr_info("Inside queue_exit function\n");
73    queue_stop();
74    return;
75}
76
77module_init(queue_init);
78module_exit(queue_exit);
1obj-m += tc4.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 380
-rw-rw-r-- 1 test test    151 Aug  2 11:47 Makefile
-rw-rw-r-- 1 test test     80 Aug  2 12:46 modules.order
-rw-rw-r-- 1 test test      0 Aug  2 12:46 Module.symvers
-rw-rw-r-- 1 test test   1715 Aug  2 11:47 tc4.c
-rw-rw-r-- 1 test test 180448 Aug  2 12:46 tc4.ko
-rw-rw-r-- 1 test test     80 Aug  2 12:46 tc4.mod
-rw-rw-r-- 1 test test   1104 Aug  2 12:46 tc4.mod.c
-rw-rw-r-- 1 test test 149288 Aug  2 12:46 tc4.mod.o
-rw-rw-r-- 1 test test  32624 Aug  2 12:46 tc4.o
  • Load the module to kernel using insmod command.

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

$ dmesg
[282424.157821] Inside queue_init function
[282424.202296] Inside workqueue_func
[282425.226337] Inside workqueue_func
[282426.250143] Inside workqueue_func
[282427.274333] Inside workqueue_func
[282428.298179] Inside workqueue_func
[282429.322313] Inside workqueue_func
[282430.346329] Inside workqueue_func
[282431.370333] Inside workqueue_func
[282432.394338] Inside workqueue_func
[282433.418338] Inside workqueue_func
  • Unload the module using rmmod command.

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

$ dmesg
[282439.203573] Inside queue_exit function
[282439.203578] Destroying workqueue