Check Workqueue
Topics in this section,
# |
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 ?
How to use below APIs ?
Here is the function prototype of the API: create_workqueue
#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);
Here is the function prototype of the API: work_pending
#include <linux/workqueue.h>
#define work_pending(work)
Here is an example of how to use the API,
work_pending(&my_work_1);
Here is the function prototype of the API: INIT_DELAYED_WORK
#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);
Here is the function prototype of the API: delayed_work_pending
#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);
Here is the function prototype of the API: cancel_delayed_work_sync
#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);
Here is the function prototype of the API: schedule_work
#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);
Here is the function prototype of the API: schedule_delayed_work
#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));
Here is the function prototype of the API: cancel_delayed_work
#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 check 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 work_pending");
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)) {
schedule_work(&my_work_1);
queue_work(my_workqueue,&my_work_1);
}
if (!work_pending(&my_work_2)) {
schedule_work(&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);
}
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 schedule_work(&my_work_1);
61 queue_work(my_workqueue,&my_work_1);
62 }
63 if (!work_pending(&my_work_2)) {
64 schedule_work(&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}
88
89/* queue_exit - executes when module is unloaded,
90 * calls queue_stop */
91
92static void __exit queue_exit(void)
93{
94 pr_info("Inside queue_exit function\n");
95 queue_stop();
96 return;
97}
98
99module_init(queue_init);
100module_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 check 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 delayed_work_pending");
Initialize the work which we are going to use in this example
INIT_WORK_ONSTACK(&my_work_1,workqueue_func_1);
INIT_WORK_ONSTACK(&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)
{
INIT_DELAYED_WORK(&my_work_1,workqueue_func_1);
INIT_DELAYED_WORK(&my_work_2,workqueue_func_2);
if (!delayed_work_pending(&my_work_1)) {
pr_info("Delayed work is not scheduled yet\n");
schedule_delayed_work(&my_work_1,msecs_to_jiffies(500));
}
schedule_delayed_work(&my_work_2,msecs_to_jiffies(500));
}
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(&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
8#define WQ_NAME "tc7_workqueue"
9
10MODULE_LICENSE("GPL");
11MODULE_AUTHOR("Linux_usr");
12MODULE_DESCRIPTION("Example of delayed_work_pending");
13
14struct delayed_work my_work_1;
15struct delayed_work my_work_2;
16void workqueue_func_1(struct work_struct *work);
17void workqueue_func_2(struct work_struct *work);
18void queue_start(void);
19void queue_stop(void);
20
21/* workqueue_func_1 - executes when work is queued to workqueue,
22 * prints a statement and sleeps for 1000ms,
23 * stops when i value is greater than 10 */
24
25void workqueue_func_1(struct work_struct *work)
26{
27 int i = 0;
28 while (i < 10) {
29 pr_info("Inside workqueue_func_1\n");
30 i++;
31 msleep(500);
32 }
33}
34
35/* workqueue_func_2 - executes when work is queued to workqueue,
36 * prints a statement and sleeps for 1000ms,
37 * stops when i value is greater than 10 */
38
39void workqueue_func_2(struct work_struct *work)
40{
41 int i = 0;
42 while (i < 10) {
43 pr_info("Inside workqueue_func_2\n");
44 i++;
45 msleep(500);
46 }
47}
48
49/* queue_start - executes during execution of queue_start,
50 * creates workqueue,
51 * intiializes work and queues to the workqueue */
52
53void queue_start(void)
54{
55 INIT_DELAYED_WORK(&my_work_1,workqueue_func_1);
56 INIT_DELAYED_WORK(&my_work_2,workqueue_func_2);
57 if (!delayed_work_pending(&my_work_1)) {
58 pr_info("Delayed work is not scheduled yet\n");
59 schedule_delayed_work(&my_work_1,msecs_to_jiffies(500));
60 }
61 schedule_delayed_work(&my_work_2,msecs_to_jiffies(500));
62}
63
64/* queue_init - executes when module is loaded,
65 * calls queue_start */
66
67static int __init queue_init(void)
68{
69 pr_info("Inside queue_init function\n");
70 queue_start();
71 return 0;
72}
73
74/* queue_stop - executes during execution of queue_exit,
75 * waits until the completion and destroys workqueue */
76
77void queue_stop(void)
78{
79 pr_info("Destroying workqueue\n");
80 cancel_delayed_work_sync(&my_work_1);
81 cancel_delayed_work(&my_work_2);
82}
83
84/* queue_exit - executes when module is unloaded,
85 * calls queue_stop */
86
87static void __exit queue_exit(void)
88{
89 pr_info("Inside queue_exit function\n");
90 queue_stop();
91 return;
92}
93
94module_init(queue_init);
95module_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 84 Aug 2 12:51 modules.order
-rw-rw-r-- 1 test test 0 Aug 2 12:51 Module.symvers
-rw-rw-r-- 1 test test 2356 Aug 2 11:47 tc2.c
-rw-rw-r-- 1 test test 181992 Aug 2 12:51 tc2.ko
-rw-rw-r-- 1 test test 84 Aug 2 12:51 tc2.mod
-rw-rw-r-- 1 test test 1103 Aug 2 12:51 tc2.mod.c
-rw-rw-r-- 1 test test 149296 Aug 2 12:51 tc2.mod.o
-rw-rw-r-- 1 test test 34160 Aug 2 12:51 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
[ 1927.976881] Inside queue_init function
[ 1927.977802] Inside workqueue_func_1
[ 1927.977886] Inside workqueue_func_2
[ 1928.986617] Inside workqueue_func_2
[ 1928.986634] Inside workqueue_func_1
[ 1930.010693] Inside workqueue_func_2
[ 1930.010731] Inside workqueue_func_1
[ 1931.034722] Inside workqueue_func_2
[ 1931.034739] Inside workqueue_func_1
[ 1932.058735] Inside workqueue_func_2
[ 1932.058751] Inside workqueue_func_1
[ 1933.082732] Inside workqueue_func_2
[ 1933.082760] Inside workqueue_func_1
[ 1934.106692] Inside workqueue_func_1
[ 1934.106709] Inside workqueue_func_2
[ 1935.130737] Inside workqueue_func_2
[ 1935.130753] Inside workqueue_func_1
[ 1936.154741] Inside workqueue_func_1
[ 1936.154758] Inside workqueue_func_2
[ 1937.178738] Inside workqueue_func_2
[ 1937.178755] 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
[ 1955.215382] Inside queue_exit function