Adding waitqueue entries to waitqueue head
Topics in this section,
Explanation of miscellaneous APIs
Example 1: Create waitqueue entry using init_waitqueue_entry
Example 2: Adding waitqueue entries using add_wait_queue
Example 3: Adding waitqueue entries using add_wait_queue_exclusive
Example 4: Adding waitqueue entries using add_wait_queue_priority
Example 5: Check for wait entries in wait queue using waitqueue_active
Example 6: Checking for any waiting waitqueue entries using wq_has_sleeper
# |
Version |
---|---|
Ubuntu |
Ubuntu 22.10 |
Kernel |
6.7.9 |
In this program, you are going to learn
How to create waitqueue?
What are the different ways to add waitqueue entries to waitqueue head?
How to wakeup the waiting threads once the task is completed?
How to use Kthread APIs ?
How to use below APIs ?
Here is the function prototype of the API: kthread_should_stop
#include <linux/kthread.h>
bool kthread_should_stop(void);
where
kthread_should_stop: this is used to determine whether the thread should return now. Whenever the kthread_stop() is called it will be woken and returns true.
return type: returns true when the thread is stopped, false when the thread is still in execution
Here is an example of how to use the API,
while (!kthread_should_stop())
{
//add the instructions to be performed during thread execution.
}
Here is the function prototype of the API: kthread_run
#include <linux/kthread.h>
#define kthread_run(threadfn, data, namefmt, ...)
where
kthread_run : is used to create and wake a kthread
return type: struct task_struct* (i.e) address of the kthread
threadfn: function to executed by kthread
data: data pointer for threadfn which can be used to send any possible arguments required for threadfn.
namefmt: printf-style format for the thread name which will be displayed on ps output when the thread is in execution.
Here is an example of how to use the API,
kthread_run(mythread,NULL,"sample kthread");
Here is the function prototype of the API: kthread_stop
#include <linux/kthread.h>
int kthread_stop(struct task_struct *k);
where
kthread_stop: stops a kthread.
return type: returns the return value of threadfn() which is passed as an argument during kthread creation.
k: kthread created by one of the API used to created kthread.
Here is the example of how to use the API,
kthread_stop(mythread);
Here is the prototype of the API: DECLARE_WAIT_QUEUE_HEAD
# include <linux/wait.h>
#define DECLARE_WAIT_QUEUE_HEAD(name) \
struct wait_queue_head name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
where
DECLARE_WAIT_QUEUE_HEAD : To declare and initialize wait queue head.
name : name which is given to the wait queue head on declaration.
Here is the example of the API,
DECLARE_WAIT_QUEUE_HEAD(mywaitqueue);
Here is the prototype of the API: init_waitqueue_entry
# include <linux/wait.h>
static inline void init_waitqueue_entry(struct wait_queue_entry *wq_entry, struct task_struct *p);
where
init_waitqueue_entry : initialize a waitqueue entry
wq_entry : waitqueue entry which is going to be initialized
p : thread to which waitqueue entry is added
Here is an example of how to use the API
init_waitqueue_entry(mywaitqueue,current);
Here is the prototype of the API: init_waitqueue_func_entry
# include <linux/wait.h>
static inline void init_waitqueue_func_entry(struct wait_queue_entry *wq_entry, wait_queue_func_t func);
where
init_waitqueue_func_entry : initialize a waitqueue entry and map user defined function to it.
wq_entry : waitqueue entry which needs to be initialized
func: user defined function which is mapped to waitqueue entry.
Here is the prototype of the API: add_wait_queue
# include <linux/wait.h>
void add_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry);
where
add_wait_queue : adding a waitqueue entry to waitqueue head.
wq_head: waitqueue head to which entry needs to be added
wq_entry: waitqueue entry to be added.
Here is an example of how to use the API,
add_wait_queue(mywq_head,mywq_entry);
Here is the prototype of the API: add_wait_queue_exclusive
# include <linux/wait.h>
void add_wait_queue_exclusive(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry);
where
add_wait_queue_exclusive : used to add wait entries to wait queue head exclusively
wq_head: waitqueue head to which entry needs to be added
wq_entry: entry to be added
Here is an example of how to use the API,
add_wait_queue_exclusive(mywq_head,mywq_entry);
Here is the prototype of the API: add_wait_queue_priority
# include <linux/wait.h>
void add_wait_queue_priority(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry);
where
add_wait_queue_priority : adding the wait entry to wait queue head in a priority manner.
wq_head: waitqueue head to which wait entry should be added.
wq_entry: waitqueue entry to be added.
Here is an example of the API,
add_wait_queue_priority (mywq_head,mywq_entry);
Here is the prototype of the API: remove_wait_queue
# include <linux/wait.h>
void remove_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry);
where
remove_wait_queue : remove a waitqueue entry from waitqueue head.
wq_head: waitqueue head from which waitqueue entry should be removed.
wq_entry: entry to be removed
Here is an example of the API,
remove_wait_queue(mywq_head,mywq_entry);
Here is the prototype of the API: waitqueue_active
# include <linux/wait.h>
int waitqueue_active(struct wait_queue_head *wq_head);
where
waitqueue_active : locklessly test for waiters on the queue.
wq_head: the waitqueue to test for waiters
return type: returns true if the wait list is not empty
Here is the prototype of the API: wq_has_sleeper
# include <linux/wait.h> bool wq_has_sleeper(struct wait_queue_head *wq_head);
where
wq_has_sleeper : check if there are any waiting processes
wq_head: wait queue head
return type: Returns true if wq_head has waiting processes
Here is the prototype of the API : wait_event_interruptible
#include <linux/wait.h>
#define wait_event_interruptible(wq_head, condition) \
({ \
int __ret = 0; \
might_sleep(); \
if (!(condition)) \
__ret = __wait_event_interruptible(wq_head, condition); \
__ret; \
})
where
wait_event_interruptible : The process is put to sleep (TASK_INTERRUPTIBLE) until the condition evaluates to true or a signal is received. The condition is checked each time the waitqueue wq_head is woken up.
wq_head : the waitqueue to wait on
condition : a C expression for the event to wait for
return type: The function will return -ERESTARTSYS if it was interrupted by a signal and 0 if condition evaluated to true.
Here is an example of how to use the API,
wait_event_interruptible(mywaitqueue,flag != 0);
Here is the prototype of the API: wake_up_interruptible
#include <linux/wait.h>
#define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)
where
wake_up_interruptible : wakes up the waitqueue head which is in waiting state.
x : waitqueue which is in waiting state.
Here is the example of how to use the API
wake_up_interruptible(mywaitqueue);
Here is the prototype of module paramter APIs
#include <linux/module.h>
#define MODULE_LICENSE(_license) MODULE_FILE MODULE_INFO(license, _license)
#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
where
MODULE_LICENSE: tells the kernel what license is used by our module.
MODULE_AUTHOR: denotes the author of this kernel module.
MODULE_DESCRIPTION: gives a basic idea about what the kernel module does.
These information can be found when modinfo command is used which lists out all these above mentioned information.
Here is the example of how to use the Module parameter APIs,
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux Usr");
MODULE_DESCRIPTION("Sample kernel module");
Here is the prototype of the API: IS_ERR
#include <linux/err.h>
static inline bool __must_check IS_ERR(__force const void *ptr);
where
IS_ERR: Detects an error pointer
return type: return true if it’s an error pointer else return false.
ptr: pointer which needs to detected.
Here is an example of how to use the API,
if(IS_ERR(sample_ptr)) {
//instructions to be executed when error ptr is detected
} else {
//instructions to be executed when error ptr is not detected
}
Here is the example of the API: wake_up_process
#include <linux/sched.h>
extern int wake_up_process(struct task_struct *tsk);
where
wake_up_process: wake up a specific process
return type: returns 1 if the process is woken up, 0 if the process is in running state.
tsk: process to be woken up.
Here is the example of how to use the API,
wake_up_process(mythread);
Here is the prototype of the Driver entry point API’s
#include <linux/module.h>
#define module_init(x) __initcall(x);
#define module_exit(x) __exitcall(x);
where
module_init: driver initialization entry point which will be called at module insertion time.
module_exit: driver exit entry point which will be called during the removal of module.
- x:
function to be run at module insertion for module_init function.
function to be run when driver is removed for module_exit function.
Here is an example of how to use the driver entry point API’s
module_init(myinitmodule);
module_exit(myexitmodule);
In this example let’s see how to create waitqueue entry using init_waitqueue_entry and use with kthread.
Include the follow header files(.h) to refer the API being used for the execution.
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/delay.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 init_waitqueue_entry");
Declare the thread and waitqueue variables which we are going to create and use in this example
static struct task_struct *wait_thread;
static struct task_struct *wake_up_thread;
static DECLARE_WAIT_QUEUE_HEAD(wqueue);
wait_queue_entry_t wait;
int wait_flag = 0;
Add the module init function which will be executed once we load the kernel module using insmod command.
static int __init init_waitqueue_entry_init(void)
{
pr_info("Inside thread init function\n");
thread_start();
return 0;
}
Add the thread start function which is called from module init function, creates the thread and starts it’s execution.
void thread_start(void)
{
wait_thread = kthread_run(wait_thread_fn,NULL,"init_waitqueue_entry wait_thread example");
if (IS_ERR(wait_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
wake_up_thread = kthread_run(wake_up_thread_fn,NULL,"init_waitqueue_entry wake_up_thread example");
if(IS_ERR(wake_up_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
}
Add the module exit function which will be executed once we unload the kernel module using rmmod command.
static void __exit init_waitqueue_entry_exit(void)
{
pr_info("Inside kthread exit function\n");
thread_stop();
}
Add the thread stop function which is called from module exit function, destroys the thread created and stops it’s execution.
void thread_stop(void)
{
kthread_stop(wake_up_thread);
kthread_stop(wait_thread);
pr_info("destroyed threads\n");
}
Add the thread function API which will be called as soon as the kthread is created and is in running state.
int wait_thread_fn(void *data)
{
init_waitqueue_entry(&wait,current);
add_wait_queue(&wqueue,&wait);
while(!kthread_should_stop()) {
wait_event_interruptible(wqueue,wait_flag != 0);
pr_info("thread 1 execution\n");
msleep(1000);
}
remove_wait_queue(&wqueue,&wait);
if (waitqueue_active(&wqueue)) {
pr_info("pending waitqueues\n");
} else {
pr_info("no more pending waitqueues\n");
}
return 0;
}
int wake_up_thread_fn(void *data)
{
while(!kthread_should_stop()) {
pr_info("thread 2 execution\n");
wait_flag = 1;
msleep(1000);
}
wake_up_interruptible(&wqueue);
return 0;
}
Add the driver entry points which will be executed once the module is inserted or removed from the kernel.
module_init(init_waitqueue_entry_init);
module_exit(init_waitqueue_entry_exit);
1#include <linux/init.h>
2#include <linux/module.h>
3#include <linux/kernel.h>
4#include <linux/kthread.h>
5#include <linux/wait.h>
6#include <linux/delay.h>
7
8MODULE_LICENSE("GPL");
9MODULE_AUTHOR("linux usr");
10MODULE_DESCRIPTION("Example of init_waitqueue_entry");
11
12static struct task_struct *wait_thread;
13static struct task_struct *wake_up_thread;
14static DECLARE_WAIT_QUEUE_HEAD(wqueue);
15wait_queue_entry_t wait;
16int wait_flag = 0;
17
18/* wait_thread_fn - executes when wait_thread is created,
19 * initialize waitqueue entry,
20 * add the waitqueue entry to waitqueue,
21 * wait for event to be completed from wake_up thread,
22 * prints a message and sleeps for 1000ms,
23 * stops when kthread_stop is called */
24
25int wait_thread_fn(void *data)
26{
27 init_waitqueue_entry(&wait,current);
28 add_wait_queue(&wqueue,&wait);
29 while(!kthread_should_stop()) {
30 wait_event_interruptible(wqueue,wait_flag != 0);
31 pr_info("thread 1 execution\n");
32 msleep(1000);
33 }
34 remove_wait_queue(&wqueue,&wait);
35 if(waitqueue_active(&wqueue)){
36 pr_info("pending waitqueues\n");
37 }else{
38 pr_info("no more pending waitqueues\n");
39 }
40 return 0;
41}
42
43/* wake_up_thread_fn - executes when wake_up thread is created,
44 * prints a message and sleeps for 1000ms,
45 * sends wake up signal to wait_thread,
46 * stops when kthread_stop is called */
47
48int wake_up_thread_fn(void *data)
49{
50 while(!kthread_should_stop()) {
51 pr_info("thread 2 execution\n");
52 wait_flag = 1;
53 msleep(1000);
54 }
55 wake_up_interruptible(&wqueue);
56 return 0;
57}
58
59/* thread_start - creates thread and starts execution */
60
61void thread_start(void)
62{
63 wait_thread = kthread_run(wait_thread_fn,NULL,"init_waitqueue_entry wait_thread example");
64 if (IS_ERR(wait_thread))
65 pr_info("error creating thread\n");
66 else
67 pr_info("kthread created successfully\n");
68 wake_up_thread = kthread_run(wake_up_thread_fn,NULL,"init_waitqueue_entry wait_thread example");
69 if(IS_ERR(wake_up_thread))
70 pr_info("error creating thread\n");
71 else
72 pr_info("kthread created successfully\n");
73}
74
75/* init_waitqueue_entry_init - calls thread_start,
76 * executes when the module is loaded */
77
78static int __init init_waitqueue_entry_init(void)
79{
80 pr_info("inside kthread init function\n");
81 thread_start();
82 return 0;
83}
84
85/* thread_stop - destroys thread and stops execution */
86
87void thread_stop(void)
88{
89 kthread_stop(wake_up_thread);
90 kthread_stop(wait_thread);
91 pr_info("destroyed threads\n");
92}
93
94/* init_waitqueue_entry_exit - calls thread_stop,
95 * executes when module is unloaded */
96
97static void __exit init_waitqueue_entry_exit(void)
98{
99 pr_info("inside kthread exit function\n");
100 thread_stop();
101}
102
103module_init(init_waitqueue_entry_init);
104module_exit(init_waitqueue_entry_exit);
1obj-m += kthread.o
2
3all:
4 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
5
6clean:
7 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Run make to compile the kernel source and generate the .ko image.
make -C /lib/modules/6.7.9/build M=$HOME/kthread_examples/
make[1]: Entering directory '/usr/src/linux-headers-6.7.9'
warning: the compiler differs from the one used to build the kernel
The kernel was built by: x86_64-linux-gnu-gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0
You are using: gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0
CC [M] $HOME/kthread_examples/kthread.o
MODPOST $HOME/kthread_examples/Module.symvers
CC [M] $HOME/kthread_examples/kthread.mod.o
LD [M] $HOME/kthread_examples/kthread.ko
BTF [M] $HOME/kthread_examples/kthread.ko
Skipping BTF generation for $HOME/kthread_examples/kthread.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-6.7.9'
Check if the .ko is generated or not using ls command.
test@test-V520-15IKL:~$ ls -l
total 360
-rw-rw-r-- 1 test test 713 Mar 18 16:06 kthread.c
-rw-rw-r-- 1 test test 169784 Mar 18 16:08 kthread.ko
-rw-rw-r-- 1 test test 58 Mar 18 16:08 kthread.mod
-rw-rw-r-- 1 test test 1047 Mar 18 16:08 kthread.mod.c
-rw-rw-r-- 1 test test 96512 Mar 18 16:08 kthread.mod.o
-rw-rw-r-- 1 test test 74696 Mar 18 16:08 kthread.o
-rw-rw-r-- 1 test test 161 Mar 18 16:00 Makefile
-rw-rw-r-- 1 test test 58 Mar 18 16:08 modules.order
-rw-rw-r-- 1 test test 0 Mar 18 16:08 Module.symvers
Run modinfo command to get the information about the kernel module.
test@test-V520-15IKL:~/.../tc_1$ modinfo kthread.ko
filename: $HOME/kthread_examples/kthread.ko
description: Example of init_waitqueue_entry
author: Linux Usr
license: GPL
srcversion: 8D2147F67AB01CF0E482DAC
depends:
retpoline: Y
name: kthread
vermagic: 6.7.9 SMP preempt mod_unload modversions
insert the module using insmod command.
test@test-V520-15IKL:~$ sudo insmod ./kthread.ko
check if the module is loaded or not using lsmod command.
test@test-V520-15IKL:~$ sudo lsmod | grep kthread
kthread 16384 0
check if the thread is created or not using ps command.
test@test-V520-15IKL:~$ ps -N | grep init_waitqueue_entry
7249 ? 00:00:00 init_waitqueue_entry wait_thread example
7250 ? 00:00:00 init_waitqueue_entry wait_thread example
check for the kernel messages from init function and thread function once the module is loaded and thread is created.
test@test-V520-15IKL:~$ sudo dmesg
[ 580.934801] inside kthread init function
[ 580.934856] kthread created successfully
[ 580.934871] kthread created successfully
[ 580.934873] thread 2 execution
[ 581.941483] thread 2 execution
remove the module from kernel using rmmod command.
test@test-V520-15IKL:~$ sudo rmmod kthread
check if the module is still loaded after removing the kernel module using lsmod if it is not displayed in lsmod output it is verified that the module is removed successfully.
test@test-V520-15IKL:~$ sudo lsmod | grep kthread
test@test-V520-15IKL:~$
check if the thread is destroyed using ps command if it is not displayed in ps output we can confirm that the thread is destroyed successfully.
test@test-V520-15IKL:~$ ps -N | grep init_waitqueue_entry
test@test-V520-15IKL:~$
Check for kernel messages from exit function using dmesg command.
test@test-V520-15IKL:~$ sudo dmesg
[ 590.988437] inside kthread exit function
[ 591.147138] thread 1 execution
[ 592.183215] no more pending waitqueues
[ 592.183249] destroyed threads
In this example let’s see how to add waitqueue entries using add_wait_queue.
Include the follow header files(.h) to refer the API being used for the execution.
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/delay.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 add_wait_queue");
Declare the thread variables which we are going to create and use in this example
static struct task_struct *wait_thread;
static struct task_struct *wake_up_thread;
static DECLARE_WAIT_QUEUE_HEAD(wqueue);
wait_queue_entry_t wait;
int wait_flag = 0;
Add the module init function which will be executed once we load the kernel module using insmod command.
static int __init add_wait_queue_init(void)
{
pr_info("Inside kthread init function\n");
thread_start();
return 0;
}
Add the thread start function called from the module init function which is used to create the thread and execute it.
void thread_start(void)
{
pr_info("initialized waitqueue head\n");
wait_thread = kthread_run(wait_thread_fn,NULL,"add_wait_queue wait_thread example");
if (IS_ERR(wait_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
wake_up_thread = kthread_run(wake_up_thread_fn,NULL,"add_wait_queue wake_up_thread example");
if(IS_ERR(wake_up_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
}
Add the module exit function which will be executed once we unload the kernel module using rmmod command.
static void __exit add_wait_queue_exit(void)
{
pr_info("Inside kthread exit function\n");
thread_stop();
}
Add the thread stop function called from the module exit function which is used to destroy the thread and stop its execution.
void thread_stop(void)
{
kthread_stop(wake_up_thread);
msleep(2000);
kthread_stop(wait_thread);
pr_info("destroyed threads\n");
}
Add the thread function API which will be called as soon as the kthread is created and is in running state.
int wait_thread_fn(void *data)
{
init_waitqueue_func_entry(&wait,waitqueue_fn);
add_wait_queue(&wqueue,&wait);
while(!kthread_should_stop()) {
wait_event_interruptible(wqueue,wait_flag != 0);
pr_info("thread 1 execution\n");
msleep(1000);
}
remove_wait_queue(&wqueue,&wait);
return 0;
}
int wake_up_thread_fn(void *data)
{
while(!kthread_should_stop()) {
pr_info("thread 2 execution\n");
msleep(1000);
}
wait_flag = 1;
wake_up(&wqueue);
return 0;
}
Add the waitqueue entry function which is mapped to the workqueue entry created.
static int waitqueue_fn(wait_queue_entry_t *wait, unsigned mode, int flags,void *key)
{
int i = 0;
while ( i < 3) {
pr_info("waitqueue fn i = %d\n",i);
i++;
}
return 0;
}
Add the driver entry points which will be executed once the module is inserted or removed from the kernel.
module_init(add_wait_queue_init);
module_exit(add_wait_queue_exit);
1#include <linux/init.h>
2#include <linux/module.h>
3#include <linux/kernel.h>
4#include <linux/kthread.h>
5#include <linux/wait.h>
6#include <linux/delay.h>
7
8MODULE_LICENSE("GPL");
9MODULE_AUTHOR("linux usr");
10MODULE_DESCRIPTION("Example of add_wait_queue");
11
12static struct task_struct *wait_thread;
13static struct task_struct *wake_up_thread;
14static DECLARE_WAIT_QUEUE_HEAD(wqueue);
15wait_queue_entry_t wait;
16int wait_flag = 0;
17
18/* waitqueue_fn - executes when the wait_entry gets wake_up signal,
19 * prints a message till i reaches 3 */
20
21static int waitqueue_fn(wait_queue_entry_t *wait, unsigned mode, int flags,void *key)
22{
23 int i = 0;
24 while ( i < 3) {
25 pr_info("waitqueue fn i = %d\n",i);
26 i++;
27 }
28 return 0;
29}
30
31/* wait_thread_fn - executes when wait_thread is created,
32 * create a waitqueue entry add it to waitqueue head,
33 * waits for event completion in wake_up thread,
34 * prints a message and sleeps for 1000ms,
35 * removes waitentry from waitqueue head,
36 * stops when kthread_stop is called */
37
38int wait_thread_fn(void *data)
39{
40 init_waitqueue_func_entry(&wait,waitqueue_fn);
41 add_wait_queue(&wqueue,&wait);
42 while(!kthread_should_stop()) {
43 wait_event_interruptible(wqueue,wait_flag != 0);
44 pr_info("thread 1 execution\n");
45 msleep(1000);
46 }
47 remove_wait_queue(&wqueue,&wait);
48 return 0;
49}
50
51/* wake_up_thread_fn - executes when wake_up_thread is created,
52 * prints a message and sleeps for 1000ms,
53 * sends wake_up signal to wait_thread to check if event is completed,
54 * stops when kthread_stop is called */
55
56int wake_up_thread_fn(void *data)
57{
58 while(!kthread_should_stop()) {
59 pr_info("thread 2 execution\n");
60 msleep(1000);
61 }
62 wait_flag = 1;
63 wake_up(&wqueue);
64 return 0;
65}
66
67/* thread_start - creates thread and starts execution */
68
69void thread_start(void)
70{
71 wait_thread = kthread_run(wait_thread_fn,NULL,"add_wait_queue wait_thread example");
72 if (IS_ERR(wait_thread))
73 pr_info("error creating thread\n");
74 else
75 pr_info("kthread created successfully\n");
76 wake_up_thread = kthread_run(wake_up_thread_fn,NULL,"add_wait_queue wake_up_thread example");
77 if(IS_ERR(wake_up_thread))
78 pr_info("error creating thread\n");
79 else
80 pr_info("kthread created successfully\n");
81}
82
83/* add_wait_queue_init - calls thread_start,
84 * executes when module is loaded */
85
86static int __init add_wait_queue_init(void)
87{
88 pr_info("inside kthread init function\n");
89 thread_start();
90 return 0;
91}
92
93/* thread_stop - destroys thread and stops execution */
94
95void thread_stop(void)
96{
97 kthread_stop(wake_up_thread);
98 msleep(2000);
99 kthread_stop(wait_thread);
100 pr_info("destroyed threads\n");
101}
102
103/* add_wait_queue_exit - calls thread_stop,
104 * executes when module is unloaded */
105
106static void __exit add_wait_queue_exit(void)
107{
108 pr_info("inside kthread exit function\n");
109 thread_stop();
110}
111
112module_init(add_wait_queue_init);
113module_exit(add_wait_queue_exit);
1obj-m += kthread.o
2
3all:
4 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
5
6clean:
7 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Run make to compile the kernel source and generate the .ko image.
make -C /lib/modules/6.7.9/build M=$HOME/kthread_examples/
make[1]: Entering directory '/usr/src/linux-headers-6.7.9'
warning: the compiler differs from the one used to build the kernel
The kernel was built by: x86_64-linux-gnu-gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0
You are using: gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0
CC [M] $HOME/kthread_examples/kthread.o
MODPOST $HOME/kthread_examples/Module.symvers
CC [M] $HOME/kthread_examples/kthread.mod.o
LD [M] $HOME/kthread_examples/kthread.ko
BTF [M] $HOME/kthread_examples/kthread.ko
Skipping BTF generation for $HOME/kthread_examples/kthread.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-6.7.9'
Check if the .ko is generated or not using ls command.
test@test-V520-15IKL:~$ ls -l
total 360
-rw-rw-r-- 1 test test 713 Mar 18 16:06 kthread.c
-rw-rw-r-- 1 test test 169784 Mar 18 16:08 kthread.ko
-rw-rw-r-- 1 test test 58 Mar 18 16:08 kthread.mod
-rw-rw-r-- 1 test test 1047 Mar 18 16:08 kthread.mod.c
-rw-rw-r-- 1 test test 96512 Mar 18 16:08 kthread.mod.o
-rw-rw-r-- 1 test test 74696 Mar 18 16:08 kthread.o
-rw-rw-r-- 1 test test 161 Mar 18 16:00 Makefile
-rw-rw-r-- 1 test test 58 Mar 18 16:08 modules.order
-rw-rw-r-- 1 test test 0 Mar 18 16:08 Module.symvers
Run modinfo command to get the information about the kernel module.
test@test-V520-15IKL:~/.../tc_1$ modinfo kthread.ko
filename: $HOME/kthread_examples/kthread.ko
description: Example of add_wait_queue
author: Linux Usr
license: GPL
srcversion: 8D2147F67AB01CF0E482DAC
depends:
retpoline: Y
name: kthread
vermagic: 6.7.9 SMP preempt mod_unload modversions
insert the module using insmod command.
test@test-V520-15IKL:~$ sudo insmod ./kthread.ko
check if the module is loaded or not using lsmod command.
test@test-V520-15IKL:~$ sudo lsmod | grep kthread
kthread 16384 0
check if the thread is created or not using ps command.
test@test-V520-15IKL:~$ ps -N | grep add_wait_queue
15147 ? 00:00:00 add_wait_queue wait_thread example
15148 ? 00:00:00 add_wait_queue wake_up_thread example
check for the kernel messages from init function and thread function once the module is loaded and thread is created.
test@test-V520-15IKL:~$ sudo dmesg
[ 4430.577931] inside kthread init function
[ 4430.578033] kthread created successfully
[ 4430.578067] kthread created successfully
[ 4430.578072] thread 2 execution
[ 4431.594784] thread 2 execution
remove the module from kernel using rmmod command.
test@test-V520-15IKL:~$ sudo rmmod kthread
check if the module is still loaded after removing the kernel module using lsmod if it is not displayed in lsmod output it is verified that the module is removed successfully.
test@test-V520-15IKL:~$ sudo lsmod | grep kthread
test@test-V520-15IKL:~$
check if the thread is destroyed using ps command if it is not displayed in ps output we can confirm that the thread is destroyed successfully.
test@test-V520-15IKL:~$ ps -N | grep add_wait_queue
test@test-V520-15IKL:~$
Check for kernel messages from exit function using dmesg command.
test@test-V520-15IKL:~$ sudo dmesg
[ 4441.938004] inside kthread exit function
[ 4442.858930] waitqueue fn i = 0
[ 4442.858937] waitqueue fn i = 1
[ 4442.858938] waitqueue fn i = 2
[ 4442.859038] thread 1 execution
[ 4443.882938] thread 1 execution
[ 4444.891076] destroyed threads
In this example let’s see how to add waitqueue entries using add_wait_queue_exclusive.
Include the follow header files(.h) to refer the API being used for the execution.
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/delay.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 add_wait_queue_exclusive");
Declare the thread and completion variables which we are going to create and use in this example
static struct task_struct *wait_thread;
static struct task_struct *wake_up_thread;
static DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wqueue);
wait_queue_entry_t wait;
int wait_flag = 0;
Add the module init function which will be executed once we load the kernel module using insmod command.
static int __init add_wait_queue_exclusive_init(void)
{
pr_info("Inside kthread init function\n");
thread_start();
return 0;
}
Add the thread start function called from module init function, which creates the thread, wakes it up and starts its execution.
void thread_start(void)
{
wait_thread = kthread_run(wait_thread_fn,NULL,"add_wait_queue_exclusive wait_thread example");
if (IS_ERR(wait_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
wake_up_thread = kthread_run(wake_up_thread_fn,NULL,"add_wait_queue_exclusive wake_up_thread example");
if(IS_ERR(wake_up_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
}
Add the module exit function which will be executed once we unload the kernel module using rmmod command.
static void __exit add_wait_queue_exclusive_exit(void)
{
pr_info("Inside kthread exit function\n");
thread_stop();
}
Add the thread stop function which is called from module exit function, which destroys the thread and stops the execution.
void thread_stop(void)
{
kthread_stop(wake_up_thread);
kthread_stop(wait_thread);
pr_info("destroyed threads\n");
}
Add the thread function API which will be called as soon as the kthread is created and is in running state.
int wait_thread_fn(void *data)
{
init_waitqueue_func_entry(&wait,waitqueue_fn);
add_wait_queue_exclusive(&wqueue,&wait);
while(!kthread_should_stop()) {
wait_event_interruptible(wqueue,wait_flag != 0);
pr_info("thread 1 execution\n");
msleep(1000);
}
remove_wait_queue(&wqueue,&wait);
return 0;
}
int wake_up_thread_fn(void *data)
{
while(!kthread_should_stop()) {
pr_info("thread 2 execution\n");
wait_flag = 1;
msleep(1000);
}
wake_up(&wqueue);
return 0;
}
Add the waitqueue entry function which is mapped to the waitqueue entry created.
static int waitqueue_fn(wait_queue_entry_t *wait, unsigned mode, int flags,void *key)
{
int i = 0;
while ( i < 3) {
pr_info("waitqueue fn i = %d\n",i);
i++;
}
return 0;
}
Add the driver entry points which will be executed once the module is inserted or removed from the kernel.
module_init(add_wait_queue_exclusive_init);
module_exit(add_wait_queue_exclusive_exit);
1#include <linux/init.h>
2#include <linux/module.h>
3#include <linux/kernel.h>
4#include <linux/kthread.h>
5#include <linux/wait.h>
6#include <linux/delay.h>
7
8MODULE_LICENSE("GPL");
9MODULE_AUTHOR("linux usr");
10MODULE_DESCRIPTION("Example of add_wait_queue_exclusive");
11
12static struct task_struct *wait_thread;
13static struct task_struct *wake_up_thread;
14static DECLARE_WAIT_QUEUE_HEAD(wqueue);
15wait_queue_entry_t wait;
16int wait_flag = 0;
17
18/* waitqueue_fn - executes when waitqueue entry gets wake_up signal and condition satisfies,
19 * prints a message until i value becomes 3 */
20
21static int waitqueue_fn(wait_queue_entry_t *wait, unsigned mode, int flags,void *key)
22{
23 int i = 0;
24 while ( i < 3) {
25 pr_info("waitqueue fn i = %d\n",i);
26 i++;
27 }
28 return 0;
29}
30
31/* wait_thread_fn - executes when wait_thread is created,
32 * waitqueue entry is created, added to waitqueue head,
33 * waits for event completion of wake_up_thread,
34 * prints a message and sleep for 1000ms,
35 * removes waitqueue entry from waitqueue head,
36 * stops when kthread_stop is called */
37
38int wait_thread_fn(void *data)
39{
40 init_waitqueue_func_entry(&wait,waitqueue_fn);
41 add_wait_queue_exclusive(&wqueue,&wait);
42 while(!kthread_should_stop()) {
43 wait_event_interruptible(wqueue,wait_flag != 0);
44 pr_info("thread 1 execution\n");
45 msleep(1000);
46 }
47 remove_wait_queue(&wqueue,&wait);
48 return 0;
49}
50
51/* wake_up_thread - executes when wake_up_thread is created,
52 * prints a message and sleeps for 1000ms,
53 * sends wake_up signal to wait_thread,
54 * stops when kthread_stop is called */
55
56int wake_up_thread_fn(void *data)
57{
58 while(!kthread_should_stop()) {
59 pr_info("thread 2 execution\n");
60 wait_flag = 1;
61 msleep(1000);
62 }
63 wake_up(&wqueue);
64 return 0;
65}
66
67/* thread_start - creates thread and starts execution */
68
69void thread_start(void)
70{
71 wait_thread = kthread_run(wait_thread_fn,NULL,"add_wait_queue_exclusive wait_thread example");
72 if (IS_ERR(wait_thread))
73 pr_info("error creating thread\n");
74 else
75 pr_info("kthread created successfully\n");
76 wake_up_thread = kthread_run(wake_up_thread_fn,NULL,"add_wait_queue_exclusive wake_up_thread example");
77 if(IS_ERR(wake_up_thread))
78 pr_info("error creating thread\n");
79 else
80 pr_info("kthread created successfully\n");
81}
82
83/* add_wait_queue_exclusive_init - calls thread_start,
84 * executes when module is loaded */
85
86static int __init add_wait_queue_exclusive_init(void)
87{
88 pr_info("inside kthread init function\n");
89 thread_start();
90 return 0;
91}
92
93/* thread_stop - destroys thread and stops execution */
94
95void thread_stop(void)
96{
97 kthread_stop(wake_up_thread);
98 kthread_stop(wait_thread);
99 pr_info("destroyed threads\n");
100}
101
102/* add_wait_queue_exclusive_exit - calls thread_stop,
103 * executes when module is unloaded */
104
105static void __exit add_wait_queue_exclusive_exit(void)
106{
107 pr_info("inside kthread exit function\n");
108 thread_stop();
109}
110
111module_init(add_wait_queue_exclusive_init);
112module_exit(add_wait_queue_exclusive_exit);
1obj-m += kthread.o
2
3all:
4 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
5
6clean:
7 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Run make to compile the kernel source and generate the .ko image.
make -C /lib/modules/6.7.9/build M=$HOME/kthread_examples/
make[1]: Entering directory '/usr/src/linux-headers-6.7.9'
warning: the compiler differs from the one used to build the kernel
The kernel was built by: x86_64-linux-gnu-gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0
You are using: gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0
CC [M] $HOME/kthread_examples/kthread.o
MODPOST $HOME/kthread_examples/Module.symvers
CC [M] $HOME/kthread_examples/kthread.mod.o
LD [M] $HOME/kthread_examples/kthread.ko
BTF [M] $HOME/kthread_examples/kthread.ko
Skipping BTF generation for $HOME/kthread_examples/kthread.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-6.7.9'
Check if the .ko is generated or not using ls command.
test@test-V520-15IKL:~$ ls -l
total 360
-rw-rw-r-- 1 test test 713 Mar 18 16:06 kthread.c
-rw-rw-r-- 1 test test 169784 Mar 18 16:08 kthread.ko
-rw-rw-r-- 1 test test 58 Mar 18 16:08 kthread.mod
-rw-rw-r-- 1 test test 1047 Mar 18 16:08 kthread.mod.c
-rw-rw-r-- 1 test test 96512 Mar 18 16:08 kthread.mod.o
-rw-rw-r-- 1 test test 74696 Mar 18 16:08 kthread.o
-rw-rw-r-- 1 test test 161 Mar 18 16:00 Makefile
-rw-rw-r-- 1 test test 58 Mar 18 16:08 modules.order
-rw-rw-r-- 1 test test 0 Mar 18 16:08 Module.symvers
Run modinfo command to get the information about the kernel module.
test@test-V520-15IKL:~/.../tc_1$ modinfo kthread.ko
filename: $HOME/kthread_examples/kthread.ko
description: Example of add_wait_queue_exclusive
author: Linux Usr
license: GPL
srcversion: 8D2147F67AB01CF0E482DAC
depends:
retpoline: Y
name: kthread
vermagic: 6.7.9 SMP preempt mod_unload modversions
insert the module using insmod command.
test@test-V520-15IKL:~$ sudo insmod ./kthread.ko
check if the module is loaded or not using lsmod command.
test@test-V520-15IKL:~$ sudo lsmod | grep kthread
kthread 16384 0
check if the thread is created or not using ps command.
test@test-V520-15IKL:~$ ps -N | grep add_wait_queue_exclusive
5995 ? 00:00:00 add_wait_queue_exclusive wait_thread example
5996 ? 00:00:00 add_wait_queue_exclusive wake_up_thread example
check for the kernel messages from init function and thread function once the module is loaded and thread is created.
test@test-V520-15IKL:~$ sudo dmesg
[ 860.339559] inside kthread init function
[ 860.339678] kthread created successfully
[ 860.339713] kthread created successfully
[ 860.339718] thread 2 execution
[ 861.360841] thread 2 execution
[ 862.384770] thread 2 execution
remove the module from kernel using rmmod command.
test@test-V520-15IKL:~$ sudo rmmod kthread
check if the module is still loaded after removing the kernel module using lsmod if it is not displayed in lsmod output it is verified that the module is removed successfully.
test@test-V520-15IKL:~$ sudo lsmod | grep kthread
test@test-V520-15IKL:~$
check if the thread is destroyed using ps command if it is not displayed in ps output we can confirm that the thread is destroyed successfully.
test@test-V520-15IKL:~$ ps -N | grep add_wait_queue_exclusive
test@test-V520-15IKL:~$
Check for kernel messages from exit function using dmesg command.
test@test-V520-15IKL:~$ sudo dmesg
[ 870.211391] inside kthread exit function
[ 870.576490] waitqueue fn i = 0
[ 870.576496] waitqueue fn i = 1
[ 870.576498] waitqueue fn i = 2
[ 870.576568] thread 1 execution
[ 871.600551] destroyed threads
In this example let’s see how to add waitqueue entries using add_wait_queue_priority.
Include the follow header files(.h) to refer the API being used for the execution.
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/delay.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 add_wait_queue_priority");
Declare the thread and completion variables which we are going to create and use in this example
static struct task_struct *wait_thread;
static struct task_struct *wake_up_thread;
static DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wqueue);
wait_queue_entry_t wait_1;
wait_queue_entry_t wait_2;
wait_queue_entry_t wait_priority;
int wait_flag = 0;
Add the module init function which will be executed once we load the kernel module using insmod command.
static int __init add_wait_queue_priority_init(void)
{
pr_info("Inside kthread init function\n");
thread_start();
return 0;
}
Add the thread start function called from module init function, which creates the thread, wakes it up and starts its execution.
void thread_start(void)
{
wait_thread = kthread_run(wait_thread_fn,NULL,"add_wait_queue_priority wait_thread example");
if (IS_ERR(wait_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
wake_up_thread = kthread_run(wake_up_thread_fn,NULL,"add_wait_queue_priority wake_up_thread example");
if(IS_ERR(wake_up_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
}
Add the module exit function which will be executed once we unload the kernel module using rmmod command.
static void __exit add_wait_queue_priority_exit(void)
{
pr_info("Inside kthread exit function\n");
thread_stop();
}
Add the thread stop function which is called from module exit function, which destroys the thread and stops the execution.
void thread_stop(void)
{
kthread_stop(wake_up_thread);
kthread_stop(wait_thread);
pr_info("destroyed threads\n");
}
Add the thread function API which will be called as soon as the kthread is created and is in running state.
int wait_thread_fn(void *data)
{
init_waitqueue_func_entry(&wait_1,waitqueue_fn);
init_waitqueue_func_entry(&wait_priority,waitqueue_priority_fn);
init_waitqueue_func_entry(&wait_2,waitqueue_fn);
add_wait_queue(&wqueue,&wait_1);
add_wait_queue_priority(&wqueue,&wait_priority);
add_wait_queue(&wqueue,&wait_2);
while(!kthread_should_stop()) {
wait_event_interruptible(wqueue,wait_flag != 0);
pr_info("thread 1 execution\n");
msleep(1000);
}
remove_wait_queue(&wqueue,&wait_1);
remove_wait_queue(&wqueue,&wait_priority);
remove_wait_queue(&wqueue,&wait_2);
return 0;
}
int wake_up_thread_fn(void *data)
{
while(!kthread_should_stop()) {
pr_info("thread 2 execution\n");
wait_flag = 1;
msleep(1000);
}
wake_up(&wqueue);
return 0;
}
Add the waitqueue entry function which is mapped to the waitqueue entry created.
static int waitqueue_priority_fn(wait_queue_entry_t *wait, unsigned mode, int flags,void *key)
{
int i = 3;
while (i > 0) {
pr_info("waitqueue priority fn i = %d\n",i);
i--;
}
return 0;
}
static int waitqueue_fn(wait_queue_entry_t *wait, unsigned mode, int flags,void *key)
{
int i = 0;
while ( i < 3) {
pr_info("waitqueue fn i = %d\n",i);
i++;
}
return 0;
}
Add the driver entry points which will be executed once the module is inserted or removed from the kernel.
module_init(add_wait_queue_priority_init);
module_exit(add_wait_queue_priority_exit);
1#include <linux/init.h>
2#include <linux/module.h>
3#include <linux/kernel.h>
4#include <linux/kthread.h>
5#include <linux/wait.h>
6#include <linux/delay.h>
7
8MODULE_LICENSE("GPL");
9MODULE_AUTHOR("linux usr");
10MODULE_DESCRIPTION("Example of add_wait_queue_priority");
11
12static struct task_struct *wait_thread;
13static struct task_struct *wake_up_thread;
14static DECLARE_WAIT_QUEUE_HEAD(wqueue);
15wait_queue_entry_t wait_1;
16wait_queue_entry_t wait_2;
17wait_queue_entry_t wait_priority;
18int wait_flag = 0;
19
20/* waitqueue_priority_fn - executes when waitentry gets wakeup signal,
21 * prints a message until i reaches 0 */
22
23static int waitqueue_priority_fn(wait_queue_entry_t *wait, unsigned mode, int flags,void *key)
24{
25 int i = 3;
26 while (i > 0) {
27 pr_info("waitqueue priority fn i = %d\n",i);
28 i--;
29 }
30 return 0;
31}
32
33/* waitqueue_fn - executes when waitentry gets wakeup signal,
34 * prints a message until i reaches 3 */
35
36static int waitqueue_fn(wait_queue_entry_t *wait, unsigned mode, int flags,void *key)
37{
38 int i = 0;
39 while ( i < 3) {
40 pr_info("waitqueue fn i = %d\n",i);
41 i++;
42 }
43 return 0;
44}
45
46/* wait_thread_fn - executes when wait_thread is created,
47 * creates waitentry, adds to waitqueue head,
48 * waits for event completion of wake_up_thread,
49 * prints a message and sleeps for 1000ms,
50 * removes waitentry from waitqueue head,
51 * stops when kthread_stop is called */
52
53int wait_thread_fn(void *data)
54{
55 init_waitqueue_func_entry(&wait_1,waitqueue_fn);
56 init_waitqueue_func_entry(&wait_priority,waitqueue_priority_fn);
57 init_waitqueue_func_entry(&wait_2,waitqueue_fn);
58 add_wait_queue(&wqueue,&wait_1);
59 add_wait_queue_priority(&wqueue,&wait_priority);
60 add_wait_queue(&wqueue,&wait_2);
61 while(!kthread_should_stop()) {
62 wait_event_interruptible(wqueue,wait_flag != 0);
63 pr_info("thread 1 execution\n");
64 msleep(1000);
65 }
66 remove_wait_queue(&wqueue,&wait_1);
67 remove_wait_queue(&wqueue,&wait_priority);
68 remove_wait_queue(&wqueue,&wait_2);
69 return 0;
70}
71
72/* wake_up_thread_fn - executes when wake_up_thread is created,
73 * prints a message and sleeps for 1000ms,
74 * sends wake_up signal for wait_thread,
75 * stops when kthread_stop is called */
76
77int wake_up_thread_fn(void *data)
78{
79 while(!kthread_should_stop()) {
80 pr_info("thread 2 execution\n");
81 wait_flag = 1;
82 msleep(1000);
83 }
84 wake_up(&wqueue);
85 return 0;
86}
87
88/* thread_start - creates thread and starts execution */
89
90void thread_start(void)
91{
92 wait_thread = kthread_run(wait_thread_fn,NULL,"add_wait_queue_priority wait_thread example");
93 if (IS_ERR(wait_thread))
94 pr_info("error creating thread\n");
95 else
96 pr_info("kthread created successfully\n");
97 wake_up_thread = kthread_run(wake_up_thread_fn,NULL,"add_wait_queue_priority wake_up_thread example");
98 if(IS_ERR(wake_up_thread))
99 pr_info("error creating thread\n");
100 else
101 pr_info("kthread created successfully\n");
102}
103
104/* add_wait_queue_priority_init - calls thread_start,
105 * executes when module is loaded */
106
107static int __init add_wait_queue_priority_init(void)
108{
109 pr_info("inside kthread init function\n");
110 thread_start();
111 return 0;
112}
113
114/* thread_stop - destroys thread and stops execution */
115
116void thread_stop(void)
117{
118 kthread_stop(wake_up_thread);
119 kthread_stop(wait_thread);
120 pr_info("destroyed threads\n");
121}
122
123/* add_wait_queue_priority_exit - calls thread_stop,
124 * executes when module is unloaded */
125
126static void __exit add_wait_queue_priority_exit(void)
127{
128 pr_info("inside kthread exit function\n");
129 thread_stop();
130}
131
132module_init(add_wait_queue_priority_init);
133module_exit(add_wait_queue_priority_exit);
1obj-m += kthread.o
2
3all:
4 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
5
6clean:
7 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Run make to compile the kernel source and generate the .ko image.
make -C /lib/modules/6.7.9/build M=$HOME/kthread_examples/
make[1]: Entering directory '/usr/src/linux-headers-6.7.9'
warning: the compiler differs from the one used to build the kernel
The kernel was built by: x86_64-linux-gnu-gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0
You are using: gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0
CC [M] $HOME/kthread_examples/kthread.o
MODPOST $HOME/kthread_examples/Module.symvers
CC [M] $HOME/kthread_examples/kthread.mod.o
LD [M] $HOME/kthread_examples/kthread.ko
BTF [M] $HOME/kthread_examples/kthread.ko
Skipping BTF generation for $HOME/kthread_examples/kthread.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-6.7.9'
Check if the .ko is generated or not using ls command.
test@test-V520-15IKL:~$ ls -l
total 360
-rw-rw-r-- 1 test test 713 Mar 18 16:06 kthread.c
-rw-rw-r-- 1 test test 169784 Mar 18 16:08 kthread.ko
-rw-rw-r-- 1 test test 58 Mar 18 16:08 kthread.mod
-rw-rw-r-- 1 test test 1047 Mar 18 16:08 kthread.mod.c
-rw-rw-r-- 1 test test 96512 Mar 18 16:08 kthread.mod.o
-rw-rw-r-- 1 test test 74696 Mar 18 16:08 kthread.o
-rw-rw-r-- 1 test test 161 Mar 18 16:00 Makefile
-rw-rw-r-- 1 test test 58 Mar 18 16:08 modules.order
-rw-rw-r-- 1 test test 0 Mar 18 16:08 Module.symvers
Run modinfo command to get the information about the kernel module.
test@test-V520-15IKL:~/.../tc_1$ modinfo kthread.ko
filename: $HOME/kthread_examples/kthread.ko
description: Example of add_wait_queue_priority
author: Linux Usr
license: GPL
srcversion: 8D2147F67AB01CF0E482DAC
depends:
retpoline: Y
name: kthread
vermagic: 6.7.9 SMP preempt mod_unload modversions
insert the module using insmod command.
test@test-V520-15IKL:~$ sudo insmod ./kthread.ko
check if the module is loaded or not using lsmod command.
test@test-V520-15IKL:~$ sudo lsmod | grep kthread
kthread 16384 0
check if the thread is created or not using ps command.
test@test-V520-15IKL:~$ ps -N | grep add_wait_queue_priority
7859 ? 00:00:00 add_wait_queue_priority wait_thread example
7860 ? 00:00:00 add_wait_queue_priority wake_up_thread example
check for the kernel messages from init function and thread function once the module is loaded and thread is created.
test@test-V520-15IKL:~$ sudo dmesg
[ 4025.593901] inside kthread init function
[ 4025.593970] kthread created successfully
[ 4025.594009] kthread created successfully
[ 4025.594014] thread 2 execution
[ 4026.625693] thread 2 execution
remove the module from kernel using rmmod command.
test@test-V520-15IKL:~$ sudo rmmod kthread
check if the module is still loaded after removing the kernel module using lsmod if it is not displayed in lsmod output it is verified that the module is removed successfully.
test@test-V520-15IKL:~$ sudo lsmod | grep kthread
test@test-V520-15IKL:~$
check if the thread is destroyed using ps command if it is not displayed in ps output we can confirm that the thread is destroyed successfully.
test@test-V520-15IKL:~$ ps -N | grep add_wait_queue_priority
test@test-V520-15IKL:~$
Check for kernel messages from exit function using dmesg command.
test@test-V520-15IKL:~$ sudo dmesg
[ 4037.183307] inside kthread exit function
[ 4037.889741] waitqueue priority fn i = 3
[ 4037.889748] waitqueue priority fn i = 2
[ 4037.889750] waitqueue priority fn i = 1
[ 4037.889755] waitqueue fn i = 0
[ 4037.889757] waitqueue fn i = 1
[ 4037.889758] waitqueue fn i = 2
[ 4037.889759] waitqueue fn i = 0
[ 4037.889760] waitqueue fn i = 1
[ 4037.889762] waitqueue fn i = 2
[ 4037.889764] thread 1 execution
[ 4038.913860] destroyed threads
In this example let’s see how to check for any waitqueue entries in waitqueue head using waitqueue_active.
Include the follow header files(.h) to refer the API being used for the execution.
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/delay.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 waitqueue_active");
Declare the thread and completion variables which we are going to create and use in this example
static struct task_struct *wait_thread;
static struct task_struct *wake_up_thread;
static DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wqueue);
wait_queue_entry_t wait_entry_1;
wait_queue_entry_t wait_entry_2;
wait_queue_entry_t wait_entry_3;
int wait_flag = 0;
Add the module init function which will be executed once we load the kernel module using insmod command.
static int __init waitqueue_active_init(void)
{
pr_info("Inside kthread init function\n");
thread_start();
return 0;
}
Add the thread start function called from module init function, which creates the thread, wakes it up and starts its execution.
void thread_start(void)
{
wait_thread = kthread_run(wait_thread_fn,NULL,"waitqueue_active wait_thread example");
if (IS_ERR(wait_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
wake_up_thread = kthread_run(wake_up_thread_fn,NULL,"waitqueue_active wake_up_thread example");
if(IS_ERR(wake_up_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
}
Add the module exit function which will be executed once we unload the kernel module using rmmod command.
static void __exit waitqueue_active_exit(void)
{
pr_info("Inside kthread exit function\n");
thread_stop();
}
Add the thread stop function which is called from module exit function, which destroys the thread and stops the execution.
void thread_stop(void)
{
kthread_stop(wake_up_thread);
kthread_stop(wait_thread);
pr_info("destroyed threads\n");
}
Add the thread function API which will be called as soon as the kthread is created and is in running state.
int wait_thread_fn(void *data)
{
init_waitqueue_func_entry(&wait_entry_1,waitqueue_fn);
init_waitqueue_func_entry(&wait_entry_2,waitqueue_fn);
init_waitqueue_func_entry(&wait_entry_3,waitqueue_fn);
add_wait_queue(&wqueue,&wait_entry_1);
add_wait_queue(&wqueue,&wait_entry_2);
add_wait_queue(&wqueue,&wait_entry_3);
while(!kthread_should_stop()) {
if (waitqueue_active(&wqueue)){
pr_info("waitqueues are pending\n");
wait_event_interruptible(wqueue,wait_flag != 0);
msleep(1000);
}
}
remove_wait_queue(&wqueue,&wait_entry_1);
remove_wait_queue(&wqueue,&wait_entry_2);
remove_wait_queue(&wqueue,&wait_entry_3);
return 0;
}
int wake_up_thread_fn(void *data)
{
while(!kthread_should_stop()) {
pr_info("thread 2 execution\n");
wait_flag = 1;
msleep(1000);
}
wake_up(&wqueue);
return 0;
}
Add the waitqueue entry function which is mapped to the waitqueue entry created.
static int waitqueue_fn(wait_queue_entry_t *wait, unsigned mode, int flags,void *key)
{
int i = 0;
while ( i < 3) {
pr_info("waitqueue fn i = %d\n",i);
i++;
}
return 0;
}
Add the driver entry points which will be executed once the module is inserted or removed from the kernel.
module_init(waitqueue_active_init);
module_exit(waitqueue_active_exit);
1#include <linux/init.h>
2#include <linux/module.h>
3#include <linux/kernel.h>
4#include <linux/kthread.h>
5#include <linux/wait.h>
6#include <linux/delay.h>
7
8MODULE_LICENSE("GPL");
9MODULE_AUTHOR("linux usr");
10MODULE_DESCRIPTION("Example of waitqueue_active");
11
12static struct task_struct *wait_thread;
13static struct task_struct *wake_up_thread;
14static DECLARE_WAIT_QUEUE_HEAD(wqueue);
15wait_queue_entry_t wait_entry_1;
16wait_queue_entry_t wait_entry_2;
17wait_queue_entry_t wait_entry_3;
18int wait_flag = 0;
19
20/* waitqueue_fn - executes when a wake_up signal to passed to wait entries,
21 * prints a message until i value reaches 3 */
22
23static int waitqueue_fn(wait_queue_entry_t *wait, unsigned mode, int flags,void *key)
24{
25 int i = 0;
26 while ( i < 3) {
27 pr_info("waitqueue fn i = %d\n",i);
28 i++;
29 }
30 return 0;
31}
32
33/* wait_thread_fn - executes when wait_thread is created,
34 * wait entries are initialized, added to wait queue head,
35 * check for any pending wait entries,
36 * waits for wake_up signal from wake_up_thread,
37 * removes wait entries from waitqueue head,
38 * stops when kthread_stop is called */
39
40int wait_thread_fn(void *data)
41{
42 init_waitqueue_func_entry(&wait_entry_1,waitqueue_fn);
43 init_waitqueue_func_entry(&wait_entry_2,waitqueue_fn);
44 init_waitqueue_func_entry(&wait_entry_3,waitqueue_fn);
45 add_wait_queue(&wqueue,&wait_entry_1);
46 add_wait_queue(&wqueue,&wait_entry_2);
47 add_wait_queue(&wqueue,&wait_entry_3);
48 while(!kthread_should_stop()) {
49 if (waitqueue_active(&wqueue)){
50 pr_info("waitqueues are pending\n");
51 wait_event_interruptible(wqueue,wait_flag != 0);
52 msleep(1000);
53 }
54 }
55 remove_wait_queue(&wqueue,&wait_entry_1);
56 remove_wait_queue(&wqueue,&wait_entry_2);
57 remove_wait_queue(&wqueue,&wait_entry_3);
58 return 0;
59}
60
61/* wake_up_thread_fn - executes when wake_up_thread is created,
62 * prints a message and sleeps for 1000ms,
63 * sends wake_up signal to wait_thread,
64 * stops when kthread_stop is called */
65
66int wake_up_thread_fn(void *data)
67{
68 while(!kthread_should_stop()) {
69 pr_info("thread 2 execution\n");
70 wait_flag = 1;
71 msleep(1000);
72 }
73 wake_up(&wqueue);
74 return 0;
75}
76
77/* thread_start - creates thread and starts execution */
78
79void thread_start(void)
80{
81 wait_thread = kthread_run(wait_thread_fn,NULL,"waitqueue_active wait_thread example");
82 if (IS_ERR(wait_thread))
83 pr_info("error creating thread\n");
84 else
85 pr_info("kthread created successfully\n");
86 wake_up_thread = kthread_run(wake_up_thread_fn,NULL,"waitqueue_active wake_up_thread example");
87 if(IS_ERR(wake_up_thread))
88 pr_info("error creating thread\n");
89 else
90 pr_info("kthread created successfully\n");
91}
92
93/* waitqueue_active_init - calls thread_start,
94 * executes when the module is loaded */
95
96static int __init waitqueue_active_init(void)
97{
98 pr_info("inside kthread init function\n");
99 thread_start();
100 return 0;
101}
102
103/* thread_stop - destroys thread and stops execution */
104
105void thread_stop(void)
106{
107 kthread_stop(wake_up_thread);
108 kthread_stop(wait_thread);
109 pr_info("destroyed threads\n");
110}
111
112/* waitqueue_active_exit - calls thread_stop,
113 * executes when the module is unloaded */
114
115static void __exit waitqueue_active_exit(void)
116{
117 pr_info("inside kthread exit function\n");
118 thread_stop();
119}
120
121module_init(waitqueue_active_init);
122module_exit(waitqueue_active_exit);
1obj-m += kthread.o
2
3all:
4 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
5
6clean:
7 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Run make to compile the kernel source and generate the .ko image.
make -C /lib/modules/6.7.9/build M=$HOME/kthread_examples/
make[1]: Entering directory '/usr/src/linux-headers-6.7.9'
warning: the compiler differs from the one used to build the kernel
The kernel was built by: x86_64-linux-gnu-gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0
You are using: gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0
CC [M] $HOME/kthread_examples/kthread.o
MODPOST $HOME/kthread_examples/Module.symvers
CC [M] $HOME/kthread_examples/kthread.mod.o
LD [M] $HOME/kthread_examples/kthread.ko
BTF [M] $HOME/kthread_examples/kthread.ko
Skipping BTF generation for $HOME/kthread_examples/kthread.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-6.7.9'
Check if the .ko is generated or not using ls command.
test@test-V520-15IKL:~$ ls -l
total 360
-rw-rw-r-- 1 test test 713 Mar 18 16:06 kthread.c
-rw-rw-r-- 1 test test 169784 Mar 18 16:08 kthread.ko
-rw-rw-r-- 1 test test 58 Mar 18 16:08 kthread.mod
-rw-rw-r-- 1 test test 1047 Mar 18 16:08 kthread.mod.c
-rw-rw-r-- 1 test test 96512 Mar 18 16:08 kthread.mod.o
-rw-rw-r-- 1 test test 74696 Mar 18 16:08 kthread.o
-rw-rw-r-- 1 test test 161 Mar 18 16:00 Makefile
-rw-rw-r-- 1 test test 58 Mar 18 16:08 modules.order
-rw-rw-r-- 1 test test 0 Mar 18 16:08 Module.symvers
Run modinfo command to get the information about the kernel module.
test@test-V520-15IKL:~/.../tc_1$ modinfo kthread.ko
filename: $HOME/kthread_examples/kthread.ko
description: Example of waitqueue_active
author: Linux Usr
license: GPL
srcversion: 8D2147F67AB01CF0E482DAC
depends:
retpoline: Y
name: kthread
vermagic: 6.7.9 SMP preempt mod_unload modversions
insert the module using insmod command.
test@test-V520-15IKL:~$ sudo insmod ./kthread.ko
check if the module is loaded or not using lsmod command.
test@test-V520-15IKL:~$ sudo lsmod | grep kthread
kthread 16384 0
check if the thread is created or not using ps command.
test@test-V520-15IKL:~$ ps -N | grep waitqueue_active
12444 ? 00:00:00 waitqueue_active wait_thread example
12445 ? 00:00:00 waitqueue_active wake_up_thread example
check for the kernel messages from init function and thread function once the module is loaded and thread is created.
test@test-V520-15IKL:~$ sudo dmesg
[15037.653923] inside kthread init function
[15037.653983] kthread created successfully
[15037.653988] waitqueues are pending
[15037.654015] kthread created successfully
[15037.654019] thread 2 execution
[15038.664157] thread 2 execution
remove the module from kernel using rmmod command.
test@test-V520-15IKL:~$ sudo rmmod kthread
check if the module is still loaded after removing the kernel module using lsmod if it is not displayed in lsmod output it is verified that the module is removed successfully.
test@test-V520-15IKL:~$ sudo lsmod | grep kthread
test@test-V520-15IKL:~$
check if the thread is destroyed using ps command if it is not displayed in ps output we can confirm that the thread is destroyed successfully.
test@test-V520-15IKL:~$ ps -N | grep waitqueue_active
test@test-V520-15IKL:~$
Check for kernel messages from exit function using dmesg command.
test@test-V520-15IKL:~$ sudo dmesg
[15053.122433] inside kthread exit function
[15054.024850] waitqueue fn i = 0
[15054.024859] waitqueue fn i = 1
[15054.024862] waitqueue fn i = 2
[15054.024864] waitqueue fn i = 0
[15054.024866] waitqueue fn i = 1
[15054.024868] waitqueue fn i = 2
[15054.024870] waitqueue fn i = 0
[15054.024872] waitqueue fn i = 1
[15054.024874] waitqueue fn i = 2
[15055.049009] destroyed threads
In this example let’s see how to check for any waiting waitqueue entries using wq_has_sleeper.
Include the follow header files(.h) to refer the API being used for the execution.
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/delay.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 wq_has_sleeper");
Declare the thread and completion variables which we are going to create and use in this example
static struct task_struct *wait_thread;
static struct task_struct *wake_up_thread;
static DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wqueue);
wait_queue_entry_t wait_entry_1;
wait_queue_entry_t wait_entry_2;
wait_queue_entry_t wait_entry_3;
int wait_flag = 0;
Add the module init function which will be executed once we load the kernel module using insmod command.
static int __init wq_has_sleeper_init(void)
{
pr_info("Inside kthread init function\n");
thread_start();
return 0;
}
Add the thread start function called from module init function, which creates the thread, wakes it up and starts its execution.
void thread_start(void)
{
wait_thread = kthread_run(wait_thread_fn,NULL,"wq_has_sleeper wait_thread example");
if (IS_ERR(wait_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
wake_up_thread = kthread_run(wake_up_thread_fn,NULL,"wq_has_sleeper wake_up_thread example");
if(IS_ERR(wake_up_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
}
Add the module exit function which will be executed once we unload the kernel module using rmmod command.
static void __exit wq_has_sleeper_exit(void)
{
pr_info("Inside kthread exit function\n");
thread_stop();
}
Add the thread stop function which is called from module exit function, which destroys the thread and stops the execution.
void thread_stop(void)
{
kthread_stop(wake_up_thread);
kthread_stop(wait_thread);
pr_info("destroyed threads\n");
}
Add the thread function API which will be called as soon as the kthread is created and is in running state.
int wait_thread_fn(void *data)
{
init_waitqueue_func_entry(&wait_entry_1,waitqueue_fn);
init_waitqueue_func_entry(&wait_entry_2,waitqueue_fn);
init_waitqueue_func_entry(&wait_entry_3,waitqueue_fn);
add_wait_queue(&wqueue,&wait_entry_1);
add_wait_queue(&wqueue,&wait_entry_2);
add_wait_queue(&wqueue,&wait_entry_3);
while(!kthread_should_stop()) {
if(wq_has_sleeper(&wqueue)) {
pr_info("waitqueue entries are pending\n");
wait_event_interruptible(wqueue,wait_flag != 0);
remove_wait_queue(&wqueue,&wait_entry_1);
remove_wait_queue(&wqueue,&wait_entry_2);
remove_wait_queue(&wqueue,&wait_entry_3);
msleep(1000);
}
}
return 0;
}
int wake_up_thread_fn(void *data)
{
while(!kthread_should_stop()) {
pr_info("thread 2 execution\n");
wait_flag = 1;
msleep(1000);
}
wake_up_interruptible(&wqueue);
return 0;
}
Add the waitqueue entry function which is mapped to the waitqueue entry created.
static int waitqueue_fn(wait_queue_entry_t *wait, unsigned mode, int flags,void *key)
{
int i = 0;
while ( i < 3) {
pr_info("waitqueue fn i = %d\n",i);
i++;
}
return 0;
}
Add the driver entry points which will be executed once the module is inserted or removed from the kernel.
module_init(wq_has_sleeper_init);
module_exit(wq_has_sleeper_exit);
1#include <linux/init.h>
2#include <linux/module.h>
3#include <linux/kernel.h>
4#include <linux/kthread.h>
5#include <linux/wait.h>
6#include <linux/delay.h>
7
8MODULE_LICENSE("GPL");
9MODULE_AUTHOR("linux usr");
10MODULE_DESCRIPTION("Example of wq_has_sleeper");
11
12static struct task_struct *wait_thread;
13static struct task_struct *wake_up_thread;
14
15static DECLARE_WAIT_QUEUE_HEAD(wqueue);
16wait_queue_entry_t wait_entry_1;
17wait_queue_entry_t wait_entry_2;
18wait_queue_entry_t wait_entry_3;
19int wait_flag = 0;
20
21/* waitqueue_fn - executes when wake_up signal is passed to wait entries,
22 * prints a message till i reaches 3 */
23
24static int waitqueue_fn(wait_queue_entry_t *wait, unsigned mode, int flags,void *key)
25{
26 int i = 0;
27 while ( i < 3) {
28 pr_info("waitqueue fn i = %d\n",i);
29 i++;
30 }
31 return 0;
32}
33
34/* wait_thread_fn - executes when wait_thread is created,
35 * initialize wait entries, add to waitqueue head,
36 * checks for any waiting wait entries,
37 * waits for wake_up signal from wake_up_thread,
38 * removes wait entries from waitqueue head,
39 * stops when kthread_stop is called */
40
41int wait_thread_fn(void *data)
42{
43 init_waitqueue_func_entry(&wait_entry_1,waitqueue_fn);
44 init_waitqueue_func_entry(&wait_entry_2,waitqueue_fn);
45 init_waitqueue_func_entry(&wait_entry_3,waitqueue_fn);
46 add_wait_queue(&wqueue,&wait_entry_1);
47 add_wait_queue(&wqueue,&wait_entry_2);
48 add_wait_queue(&wqueue,&wait_entry_3);
49 while(!kthread_should_stop()) {
50 if(wq_has_sleeper(&wqueue)) {
51 pr_info("waitqueue entries are pending\n");
52 wait_event_interruptible(wqueue,wait_flag != 0);
53 remove_wait_queue(&wqueue,&wait_entry_1);
54 remove_wait_queue(&wqueue,&wait_entry_2);
55 remove_wait_queue(&wqueue,&wait_entry_3);
56 msleep(1000);
57 }
58 }
59 return 0;
60}
61
62/* wake_up_thread - executes when wake_up_thread is called,
63 * prints a message and sleeps for 1000ms,
64 * sends wake_up signal to wait_thread,
65 * stops when kthread_stop is called */
66
67int wake_up_thread_fn(void *data)
68{
69 while(!kthread_should_stop()) {
70 pr_info("thread 2 execution\n");
71 wait_flag = 1;
72 msleep(1000);
73 }
74 wake_up(&wqueue);
75 return 0;
76}
77
78/* thread_start - creates thread and starts execution */
79
80void thread_start(void)
81{
82 wait_thread = kthread_run(wait_thread_fn,NULL,"wq_has_sleeper wait_thread example");
83 if (IS_ERR(wait_thread))
84 pr_info("error creating thread\n");
85 else
86 pr_info("kthread created successfully\n");
87 wake_up_thread = kthread_run(wake_up_thread_fn,NULL,"wq_has_sleeper wake_up_thread example");
88 if(IS_ERR(wake_up_thread))
89 pr_info("error creating thread\n");
90 else
91 pr_info("kthread created successfully\n");
92}
93
94/* wq_has_sleeper_init - calls thread_start,
95 * executes when the module is loaded */
96
97static int __init wq_has_sleeper_init(void)
98{
99 pr_info("inside kthread init function\n");
100 thread_start();
101 return 0;
102}
103
104/* thread_stop - destroys thread and stops execution */
105
106void thread_stop(void)
107{
108 kthread_stop(wake_up_thread);
109 kthread_stop(wait_thread);
110 pr_info("destroyed threads\n");
111}
112
113/* wq_has_sleeper_exit - calls thread_stop,
114 * executes when the module is unloaded */
115
116static void __exit wq_has_sleeper_exit(void)
117{
118 pr_info("inside kthread exit function\n");
119 thread_stop();
120}
121
122module_init(wq_has_sleeper_init);
123module_exit(wq_has_sleeper_exit);
1obj-m += kthread.o
2
3all:
4 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
5
6clean:
7 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Run make to compile the kernel source and generate the .ko image.
make -C /lib/modules/6.7.9/build M=$HOME/kthread_examples/
make[1]: Entering directory '/usr/src/linux-headers-6.7.9'
warning: the compiler differs from the one used to build the kernel
The kernel was built by: x86_64-linux-gnu-gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0
You are using: gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0
CC [M] $HOME/kthread_examples/kthread.o
MODPOST $HOME/kthread_examples/Module.symvers
CC [M] $HOME/kthread_examples/kthread.mod.o
LD [M] $HOME/kthread_examples/kthread.ko
BTF [M] $HOME/kthread_examples/kthread.ko
Skipping BTF generation for $HOME/kthread_examples/kthread.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-6.7.9'
Check if the .ko is generated or not using ls command.
test@test-V520-15IKL:~$ ls -l
total 360
-rw-rw-r-- 1 test test 713 Mar 18 16:06 kthread.c
-rw-rw-r-- 1 test test 169784 Mar 18 16:08 kthread.ko
-rw-rw-r-- 1 test test 58 Mar 18 16:08 kthread.mod
-rw-rw-r-- 1 test test 1047 Mar 18 16:08 kthread.mod.c
-rw-rw-r-- 1 test test 96512 Mar 18 16:08 kthread.mod.o
-rw-rw-r-- 1 test test 74696 Mar 18 16:08 kthread.o
-rw-rw-r-- 1 test test 161 Mar 18 16:00 Makefile
-rw-rw-r-- 1 test test 58 Mar 18 16:08 modules.order
-rw-rw-r-- 1 test test 0 Mar 18 16:08 Module.symvers
Run modinfo command to get the information about the kernel module.
test@test-V520-15IKL:~/.../tc_1$ modinfo kthread.ko
filename: $HOME/kthread_examples/kthread.ko
description: Example of wq_has_sleeper
author: Linux Usr
license: GPL
srcversion: 8D2147F67AB01CF0E482DAC
depends:
retpoline: Y
name: kthread
vermagic: 6.7.9 SMP preempt mod_unload modversions
insert the module using insmod command.
test@test-V520-15IKL:~$ sudo insmod ./kthread.ko
check if the module is loaded or not using lsmod command.
test@test-V520-15IKL:~$ sudo lsmod | grep kthread
kthread 16384 0
check if the thread is created or not using ps command.
test@test-V520-15IKL:~$ ps -N | grep wq_has_sleeper
16077 ? 00:00:00 wq_has_sleeper wait_thread example
16078 ? 00:00:00 wq_has_sleeper wake_up_thread example
check for the kernel messages from init function and thread function once the module is loaded and thread is created.
test@test-V520-15IKL:~$ sudo dmesg
[18271.224100] inside kthread init function
[18271.224171] kthread created successfully
[18271.224179] waitqueue entries are pending
[18271.224208] kthread created successfully
[18271.224216] thread 2 execution
[18272.255559] thread 2 execution
remove the module from kernel using rmmod command.
test@test-V520-15IKL:~$ sudo rmmod kthread
check if the module is still loaded after removing the kernel module using lsmod if it is not displayed in lsmod output it is verified that the module is removed successfully.
test@test-V520-15IKL:~$ sudo lsmod | grep kthread
test@test-V520-15IKL:~$
check if the thread is destroyed using ps command if it is not displayed in ps output we can confirm that the thread is destroyed successfully.
test@test-V520-15IKL:~$ ps -N | grep wq_has_sleeper
test@test-V520-15IKL:~$
Check for kernel messages from exit function using dmesg command.
test@test-V520-15IKL:~$ sudo dmesg
[18280.647574] inside kthread exit function
[18281.473143] waitqueue fn i = 0
[18281.473150] waitqueue fn i = 1
[18281.473151] waitqueue fn i = 2
[18281.473153] waitqueue fn i = 0
[18281.473154] waitqueue fn i = 1
[18281.473155] waitqueue fn i = 2
[18281.473156] waitqueue fn i = 0
[18281.473157] waitqueue fn i = 1
[18281.473158] waitqueue fn i = 2
[18282.497421] destroyed threads
kthread API |
Learning |
---|---|
kthread_run |
Create and wake a thread |
kthread_should_stop |
To determine when thread should exit |
kthread_stop |
Stop a thread created by kthread_create |
Waitqueue API |
Learning |
---|---|
DECLARE_WAIT_QUEUE_HEAD |
Declare waitqueue head |
init_waitqueue_entry |
Initialize a waitqueue entry |
init_waitqueue_func_entry |
Initialize a waitqueue entry and map a function to it |
add_wait_queue |
Add waitqueue entry to waitqueue head |
add_wait_queue_exclusive |
Add waitqueue entry to waitqueue head exclusively |
add_wait_queue_priority |
Add waitqueue entry to waitqueue head on priority manner |
remove_wait_queue |
Remove waitqueue entry from waitqueue head |
waitqueue_active |
locklessly test for waiters on the queue |
wq_has_sleeper |
check if there are any waiting processes |
wake_up |
wake up the waiting waitqueues under wait_event APIs |
wait_event_interruptible |
sleep until a condition gets true |
wake_up_event_interruptible |
wakes up the waiting queue |
API |
Learning |
---|---|
MODULE_LICENSE |
Used to denote the license used in the kernel module |
MODULE_AUTHOR |
Used to mention the author of the kernel module |
MODULE_DESCRIPTION |
Used to describe what the module does |
IS_ERR |
Detects an error pointer |
wake_up_process |
wake up a specific process |
msleep |
will put in sleep for a certain amount of msecs time. |
module_init |
Driver initialization entry point |
module_exit |
Driver exit entry point |
pr_info |
Print an info-level message |