Create Static Work
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 Workqueue APIs ?
How to use below APIs ?
Here is the function prototype of the API: DECLARE_WORK
#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);
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);
Here is the function prototype of the API: DECLARE_DELAYED_WORK
#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);
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_1,msecs_to_jiffies(100));
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);
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