Wait Event APIs
Topics in this section,
Explanation of miscellaneous APIs
Example 1: Waiting for an event using wait_event
Example 2: Waiting for an event using wait_event_timeout
Example 3: Waiting using prepare_to_wait
Example 4: Waiting using prepare_to_wait_exclusive
Example 5: Waiting using prepare_to_wait_event
Example 6: Waiting and waking up using wait_woken
# |
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: DEFINE_WAIT
# include <linux/wait.h>
#define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, autoremove_wake_function)
where
DEFINE_WAIT : Used to define wait queue entry
name : wait queue entry name which needs to be initialized
Here is the example of the API
DEFINE_WAIT(mywait);
Here is the prototype of the API: wait_event
# include <linux/wait.h>
#define wait_event(wq_head, condition)
where
wait_event : The process is put to sleep (TASK_UNINTERRUPTIBLE) until the condition evaluates to true. 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
Here is an example of the API
wait_event(mywq_head,i < 10);
Here is the prototype of the API: wait_event_timeout
# include <linux/wait.h>
#define wait_event_timeout(wq_head, condition, timeout)
where
wait_event_timeout : sleep until a condition gets true or a timeout elapses
wq_head: the waitqueue to wait on
condition: a C expression for the event to wait for
timeout: timeout, in jiffies
return type: 0 if the condition evaluated to false after the timeout elapsed, 1 if the condition evaluated to true after the @timeout elapsed, or the remaining jiffies (at least 1) if the condition evaluated to true before the timeout elapsed.
Here is the prototype of the API: prepare_to_wait
# include <linux/wait.h>
void prepare_to_wait(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry, int state);
where
prepare_to_wait : used to put waitqueue head in waiting state and will execute when wake_up is called.
wq_head : waitqueue head to be waited
wq_entry: entry of the waitqueue head
state: state at which it should be set while waiting
Here is an example of the API
prepare_to_wait(mywq_head,mywq_entry,TASK_UNINTERRUPTIBLE);
Here is the prototype of the API: prepare_to_wait_exclusive
# include <linux/wait.h>
bool prepare_to_wait_exclusive(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry, int state);
where
prepare_to_wait_exclusive : puts waitqueue head in waiting state till wake_up is called.
wq_head: waitqueue head to be waited
wq_entry: waitqueue descriptor
state: state at which it should be set while waiting
Here is an example of how to use the API
prepare_to_wait_exclusive(mywq_head,mywq_entry,TASK_UNINTERRUPTIBLE);
Here is the prototype of the API: prepare_to_wait_event
# include <linux/wait.h>
long prepare_to_wait_event(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry, int state);
where
prepare_to_wait_event : puts waitqueue in waiting state till wake_up is called.
wq_head: waitqueue head to be waited
wq_entry: waitqueue descriptor
state: state at which it should be set while waiting
Here is an example of how to use the API
prepare_to_wait_event(mywq_head,mywq_entry,TASK_UNINTERRUPTIBLE)
Here is the prototype of the API: finish_wait
# include <linux/wait.h>
void finish_wait(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry);
where
finish_wait : clean up after waiting in a queue
wq_head: waitqueue waited on
wq_entry: wait descriptor
Here is an example of how to use the API
finish_wait(mywq_head,mywq_entry);
Here is the prototype of the API: wait_woken
# include <linux/wait.h>
long wait_woken(struct wait_queue_entry *wq_entry, unsigned mode, long timeout);
where
wait_woken : puts in waiting state and wakes up when the timer gets expire.
wq_entry: waitqueue description
mode: state at which it is set during waiting state
timeout: timer until which it stays in waiting state
Here is an example of how to use the API
wait_woken(mywait,TASK_UNINTERRUPTIBLE,msecs_to_jiffies(100));
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 wait for an event using wait_event 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 wait_event");
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_thread;
static DECLARE_WAIT_QUEUE_HEAD(wqueue);
int i = 0;
Add the module init function which will be executed once we load the kernel module using insmod command.
static int __init wait_event_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)
{
wake_thread = kthread_run(wake_thread_fn,NULL,"wait_event wake_thread example");
if (IS_ERR(wake_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
wait_thread = kthread_run(wait_thread_fn,NULL,"wait_event wait_thread example");
if(IS_ERR(wait_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 wait_event_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_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) {
while(!kthread_should_stop()) {
wait_event(wqueue,i > 3);
pr_info("wait thread execution i value = %d\n",i);
msleep(1000);
}
return 0;
}
int wake_thread_fn(void *data)
{
while(!kthread_should_stop()) {
pr_info("wake thread execution i value = %d\n",i);
i++;
wake_up(&wqueue);
msleep(1000);
}
return 0;
}
Add the driver entry points which will be executed once the module is inserted or removed from the kernel.
module_init(wait_event_init);
module_exit(wait_event_exit);
1#include <linux/module.h>
2#include <linux/init.h>
3#include <linux/kernel.h>
4#include <linux/kthread.h>
5#include <linux/delay.h>
6
7MODULE_LICENSE("GPL");
8MODULE_AUTHOR("linux usr");
9MODULE_DESCRIPTION("Example of wait_event");
10
11static struct task_struct *wait_thread;
12static struct task_struct *wake_thread;
13DECLARE_WAIT_QUEUE_HEAD(wqueue);
14int i = 0;
15
16/* wait_thread_fn - executes when wait_thread is created,
17 * waits for the event to be completed by wake_thread,
18 * prints a message and sleeps for 1000ms,\
19 * stops when kthread_stop is called */
20
21int wait_thread_fn(void *data) {
22 while(!kthread_should_stop()) {
23 wait_event(wqueue,i > 3);
24 pr_info("wait thread execution i value = %d\n",i);
25 msleep(1000);
26 }
27 return 0;
28}
29
30/* wake_thread_fn - executes when wake_thread is created,
31 * prints a message, increments i value and sleeps for 1000ms,
32 * whenever i is incremented wake_up signal is passed to wait_thread to check for condition,
33 * stops when kthread_stop is called */
34
35int wake_thread_fn(void *data)
36{
37 while(!kthread_should_stop()) {
38 pr_info("wake thread execution i value = %d\n",i);
39 i++;
40 wake_up(&wqueue);
41 msleep(1000);
42 }
43 return 0;
44}
45
46/* thread_start - creates thread and starts execution */
47
48void thread_start(void)
49{
50 wake_thread = kthread_run(wake_thread_fn,NULL,"wait_event wake_thread example");
51 if (IS_ERR(wake_thread))
52 pr_info("error in creating wake thread\n");
53 else
54 pr_info("successfully created wake thread\n");
55 wait_thread = kthread_run(wait_thread_fn,NULL,"wait_event wait_thread example");
56 if (IS_ERR(wait_thread))
57 pr_info("error in creating wait thread\n");
58 else
59 pr_info("successfully created wait thread\n");
60}
61
62/* wait_event_init - calls thread_start,
63 * executes when module is loaded */
64
65static int __init wait_event_init(void)
66{
67 pr_info("inside kthread init function\n");
68 thread_start();
69 return 0;
70}
71
72/* thread_stop - destroys thread and stops execution */
73
74void thread_stop(void)
75{
76 kthread_stop(wake_thread);
77 kthread_stop(wait_thread);
78 pr_info("destroyed threads and completed tasks\n");
79}
80
81/* wait_event_exit - calls thread_stop,
82 * executes when module is unloaded */
83
84static void __exit wait_event_exit(void)
85{
86 pr_info("inside thread exit function\n");
87 thread_stop();
88}
89
90module_init(wait_event_init);
91module_exit(wait_event_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 wait_event
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 wait_event
10918 ? 00:00:00 wait_event wake_thread example
10919 ? 00:00:00 wait_event 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
[ 2888.995943] inside kthread init function
[ 2888.996075] successfully created wake thread
[ 2888.996081] wake thread execution i value = 0
[ 2888.996117] successfully created wait thread
[ 2890.027417] wake thread execution i value = 1
[ 2891.051318] wake thread execution i value = 2
[ 2892.075206] wake thread execution i value = 3
[ 2892.075312] wait thread execution i value = 4
[ 2893.099073] wake thread execution i value = 4
[ 2893.099156] wait thread execution i value = 5
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 wait_event
test@test-V520-15IKL:~$
Check for kernel messages from exit function using dmesg command.
test@test-V520-15IKL:~$ sudo dmesg
[ 2894.667898] inside thread exit function
[ 2896.170898] destroyed threads and completed tasks
In this example let’s see how to wait for an event using wait_event_timeout.
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 wait_event_timeout");
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_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 wait_event_timeout_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");
wake_thread = kthread_run(wake_thread_fn,NULL,"wait_event_timeout wake_thread example");
if (IS_ERR(wake_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
wait_thread = kthread_run(wait_thread_fn,NULL,"wait_event_timeout wait_thread example");
if(IS_ERR(wait_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 wait_event_timeout_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_thread);
kthread_stop(wait_thread);
pr_info("destroyed threads and completed tasks\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) {
while(!kthread_should_stop()) {
wait_event_timeout(wqueue,i > 100,msecs_to_jiffies(1000));
pr_info("wait thread execution i value = %d\n",i);
msleep(1000);
}
return 0;
}
int wake_thread_fn(void *data)
{
while(!kthread_should_stop()) {
pr_info("wake thread execution i value = %d\n",i);
i++;
wake_up(&wqueue);
msleep(1000);
}
return 0;
}
Add the driver entry points which will be executed once the module is inserted or removed from the kernel.
module_init(wait_event_timeout_init);
module_exit(wait_event_timeout_exit);
1#include <linux/module.h>
2#include <linux/init.h>
3#include <linux/kernel.h>
4#include <linux/kthread.h>
5#include <linux/delay.h>
6
7MODULE_LICENSE("GPL");
8MODULE_AUTHOR("linux usr");
9MODULE_DESCRIPTION("Example of wait_event_timeout");
10
11static struct task_struct *wait_thread;
12static struct task_struct *wake_thread;
13DECLARE_WAIT_QUEUE_HEAD(wqueue);
14int i = 0;
15
16/* wait_thread_fn - executes when wait_thread is created,
17 * waits for the event to be completed or until timer gets expired,
18 * prints a message and sleeps for 1000ms,
19 * stops when kthread_stop is called */
20
21int wait_thread_fn(void *data) {
22 while(!kthread_should_stop()) {
23 wait_event_timeout(wqueue,i > 100,msecs_to_jiffies(1000));
24 pr_info("wait thread execution i value = %d\n",i);
25 msleep(1000);
26 }
27 return 0;
28}
29
30/* wake_thread_fn - executes when wake_thread is created,
31 * prints a message, increments i value and sleeps for 1000ms,
32 * whenever i value is changed wake_up signal is passed to wait_thread to check for condition,
33 * stops when kthread_stop is called */
34
35int wake_thread_fn(void *data)
36{
37 while(!kthread_should_stop()) {
38 pr_info("wake thread execution i value = %d\n",i);
39 i++;
40 wake_up(&wqueue);
41 msleep(1000);
42 }
43 return 0;
44}
45
46/* thread_start - creates thread and starts execution */
47
48void thread_start(void)
49{
50 wake_thread = kthread_run(wake_thread_fn,NULL,"wait_event_timeout wake_thread example");
51 if (IS_ERR(wake_thread))
52 pr_info("error in creating wake thread\n");
53 else
54 pr_info("successfully created wake thread\n");
55 wait_thread = kthread_run(wait_thread_fn,NULL,"wait_event_timeout wait_thread example");
56 if (IS_ERR(wait_thread))
57 pr_info("error in creating wait thread\n");
58 else
59 pr_info("successfully created wait thread\n");
60}
61
62/* wait_event_timeout - calls thread_start,
63 * executes when module is loaded */
64
65static int __init wait_event_timeout_init(void)
66{
67 pr_info("inside kthread init function\n");
68 thread_start();
69 return 0;
70}
71
72/* thread_stop - destroys thread and stops execution */
73
74void thread_stop(void)
75{
76 kthread_stop(wake_thread);
77 kthread_stop(wait_thread);
78 pr_info("destroyed threads and completed tasks\n");
79}
80
81/* wait_event_timeout_exit - calls thread_stop,
82 * executes when module is unloaded */
83
84static void __exit wait_event_timeout_exit(void)
85{
86 pr_info("inside kthread exit function\n");
87 thread_stop();
88}
89
90module_init(wait_event_timeout_init);
91module_exit(wait_event_timeout_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 wait_event_timeout
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 wait_event_timeout
15015 ? 00:00:00 wait_event_timeout wake_thread example
15016 ? 00:00:00 wait_event_timeout 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
[ 5993.812634] inside kthread init function
[ 5993.812659] successfully created wake thread
[ 5993.812660] wake thread execution i value = 0
[ 5993.812676] successfully created wait thread
[ 5994.838087] wake thread execution i value = 1
[ 5994.838086] wait thread execution i value = 1
[ 5995.862214] wake thread execution i value = 2
[ 5996.886288] wake thread execution i value = 3
[ 5996.886297] wait thread execution i value = 4
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 wait_event_timeout
test@test-V520-15IKL:~$
Check for kernel messages from exit function using dmesg command.
test@test-V520-15IKL:~$ sudo dmesg
[ 6003.196103] inside kthread exit function
[ 6006.103486] destroyed threads and completed tasks
In this example let’s see how to wait using prepare_to_wait
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 prepare_to_wait");
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_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 prepare_to_wait_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)
{
wake_thread = kthread_run(wake_thread_fn,NULL,"prepare_to_wait wake_thread example");
if (IS_ERR(wake_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
wait_thread = kthread_run(wait_thread_fn,NULL,"prepare_to_wait wait_thread example");
if(IS_ERR(wait_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 prepare_to_wait_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_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)
{
DEFINE_WAIT(wait);
while(!kthread_should_stop()) {
prepare_to_wait(&wqueue,&wait,TASK_INTERRUPTIBLE);
schedule();
pr_info("wait thread execution i value = %d\n",i);
msleep(1000);
}
finish_wait(&wqueue,&wait);
return 0;
}
int wake_thread_fn(void *data)
{
while(!kthread_should_stop()) {
pr_info("wake thread execution i value = %d\n",i);
i++;
wake_up(&wqueue);
msleep(1000);
}
return 0;
}
Add the driver entry points which will be executed once the module is inserted or removed from the kernel.
module_init(prepare_to_wait_init);
module_exit(prepare_to_wait_exit);
1#include <linux/module.h>
2#include <linux/init.h>
3#include <linux/kernel.h>
4#include <linux/kthread.h>
5#include <linux/delay.h>
6
7MODULE_LICENSE("GPL");
8MODULE_AUTHOR("linux usr");
9MODULE_DESCRIPTION("Example of prepare_to_wait");
10
11static struct task_struct *wait_thread;
12static struct task_struct *wake_thread;
13DECLARE_WAIT_QUEUE_HEAD(wqueue);
14struct wait_queue_entry wait;
15int i = 0;
16
17/* wait_thread_fn - executes when wait_thread is created,
18 * puts the thread in waiting state will execute whenever wake_up is called,
19 * prints a message and sleeps for 1000ms,
20 * stops when kthread_stop is called */
21
22int wait_thread_fn(void *data)
23{
24 DEFINE_WAIT(wait);
25 while(!kthread_should_stop()) {
26 prepare_to_wait(&wqueue,&wait,TASK_INTERRUPTIBLE);
27 schedule();
28 pr_info("wait thread execution i value = %d\n",i);
29 msleep(1000);
30 }
31 finish_wait(&wqueue,&wait);
32 return 0;
33}
34
35/* wake_thread_fn - executes when wake_thread is created,
36 * prints a message, increments i and sleeps for 1000ms,
37 * stops when kthread_stop is called */
38
39int wake_thread_fn(void *data)
40{
41 while(!kthread_should_stop()) {
42 pr_info("wake thread execution i value = %d\n",i);
43 i++;
44 wake_up(&wqueue);
45 msleep(1000);
46 }
47 return 0;
48}
49
50/* thread_start - creates thread and starts execution */
51
52void thread_start(void)
53{
54 wake_thread = kthread_run(wake_thread_fn,NULL,"prepare_to_wait wake_thread example");
55 if (IS_ERR(wake_thread))
56 pr_info("error in creating wake thread\n");
57 else
58 pr_info("successfully created wake thread\n");
59 wait_thread = kthread_run(wait_thread_fn,NULL,"prepare_to_wait wait_thread example");
60 if (IS_ERR(wait_thread))
61 pr_info("error in creating wait thread\n");
62 else
63 pr_info("successfully created wait thread\n");
64}
65
66/* prepare_to_wait_init - calls thread_start,
67 * executes when the module is loaded */
68
69static int __init prepare_to_wait_init(void)
70{
71 pr_info("inside kthread init function\n");
72 thread_start();
73 return 0;
74}
75
76/* thread_stop - destroys thread and stops execution */
77
78void thread_stop(void)
79{
80 kthread_stop(wake_thread);
81 kthread_stop(wait_thread);
82 pr_info("destroyed threads and completed tasks\n");
83}
84
85/* prepare_to_wait_exit - calls thread_exit,
86 * executes when the module is unloaded */
87
88static void __exit prepare_to_wait_exit(void)
89{
90 pr_info("inside kthread exit function\n");
91 thread_stop();
92}
93
94module_init(prepare_to_wait_init);
95module_exit(prepare_to_wait_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 prepare_to_wait
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 prepare_to_wait
7662 ? 00:00:00 prepare_to_wait wake_thread example
7663 ? 00:00:00 prepare_to_wait 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
[ 1319.765501] inside kthread init function
[ 1319.765565] successfully created wake thread
[ 1319.765572] wake thread execution i value = 0
[ 1319.765613] successfully created wait thread
[ 1320.797801] wake thread execution i value = 1
[ 1320.797872] wait thread execution i value = 2
[ 1321.825765] wake thread execution i value = 2
[ 1321.825871] wait thread execution i value = 3
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 prepare_to_wait
test@test-V520-15IKL:~$
Check for kernel messages from exit function using dmesg command.
test@test-V520-15IKL:~$ sudo dmesg
[ 1330.817383] inside kthread exit function
[ 1331.021672] destroyed threads and completed tasks
In this example let’s see how to wait using prepare_to_wait_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 prepare_to_wait_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_thread;
DECLARE_WAIT_QUEUE_HEAD(wqueue);
struct wait_queue_entry 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 prepare_to_wait_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)
{
wake_thread = kthread_run(wake_thread_fn,NULL,"prepare_to_wait_exclusive wake_thread example");
if (IS_ERR(wake_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
wait_thread = kthread_run(wait_thread_fn,NULL,"prepare_to_wait_exclusive wait_thread example");
if(IS_ERR(wait_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 prepare_to_wait_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_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)
{
DEFINE_WAIT(wait);
while(!kthread_should_stop()) {
prepare_to_wait_exclusive(&wqueue,&wait,TASK_INTERRUPTIBLE);
schedule();
pr_info("wait thread execution i value = %d\n",i);
msleep(1000);
}
finish_wait(&wqueue,&wait);
return 0;
}
int wake_thread_fn(void *data)
{
while(!kthread_should_stop()) {
pr_info("wake thread execution i value = %d\n",i);
i++;
wake_up(&wqueue);
msleep(1000);
}
return 0;
}
Add the driver entry points which will be executed once the module is inserted or removed from the kernel.
module_init(prepare_to_wait_exclusive_init);
module_exit(prepare_to_wait_exclusive_exit);
1#include <linux/module.h>
2#include <linux/init.h>
3#include <linux/kernel.h>
4#include <linux/kthread.h>
5#include <linux/delay.h>
6
7MODULE_LICENSE("GPL");
8MODULE_AUTHOR("linux usr");
9MODULE_DESCRIPTION("Example of prepare_to_wait_exclusive");
10
11static struct task_struct *wait_thread;
12static struct task_struct *wake_thread;
13DECLARE_WAIT_QUEUE_HEAD(wqueue);
14struct wait_queue_entry wait;
15int i = 0;
16
17/* wait_thread_fn - executes when wait_thread is created,
18 * puts the wq_head in waiting state,
19 * prints a message and sleeps for 1000ms,
20 * stops when kthread_stop is called */
21
22int wait_thread_fn(void *data)
23{
24 DEFINE_WAIT(wait);
25 while(!kthread_should_stop()) {
26 prepare_to_wait_exclusive(&wqueue,&wait,TASK_INTERRUPTIBLE);
27 schedule();
28 pr_info("wait thread execution i value = %d\n",i);
29 msleep(1000);
30 }
31 finish_wait(&wqueue,&wait);
32 return 0;
33}
34
35/* wake_thread_fn - executes when wake_thread is created,
36 * prints a message, increments i value and sleeps for 1000ms,
37 * sends wake_up to wait_thread to execute,
38 * stops when kthread_stop is called */
39
40int wake_thread_fn(void *data)
41{
42 while(!kthread_should_stop()) {
43 pr_info("wake thread execution i value = %d\n",i);
44 i++;
45 wake_up(&wqueue);
46 msleep(1000);
47 }
48 return 0;
49}
50
51/* thread_start - creates thread and starts execution */
52
53void thread_start(void)
54{
55 wake_thread = kthread_run(wake_thread_fn,NULL,"prepare_to_wait_exclusive wake_thread example");
56 if (IS_ERR(wake_thread))
57 pr_info("error in creating wake thread\n");
58 else
59 pr_info("successfully created wake thread\n");
60 wait_thread = kthread_run(wait_thread_fn,NULL,"prepare_to_wait_exclusive wait_thread example");
61 if (IS_ERR(wait_thread))
62 pr_info("error in creating wait thread\n");
63 else
64 pr_info("successfully created wait thread\n");
65}
66
67/* prepare_to_wait_exclusive_init - calls thread_start,
68 * executes when the module is loaded */
69
70static int __init prepare_to_wait_exclusive_init(void)
71{
72 pr_info("inside kthread init function\n");
73 thread_start();
74 return 0;
75}
76
77/* thread_stop - destroys thread and stops execution */
78
79void thread_stop(void)
80{
81 kthread_stop(wake_thread);
82 kthread_stop(wait_thread);
83 pr_info("destroyed threads and completed tasks\n");
84}
85
86/* prepare_to_wait_exclsuive_exit - calls thread_stop,
87 * executes when the module is unloaded */
88
89static void __exit prepare_to_wait_exclusive_exit(void)
90{
91 pr_info("inside kthread exit function\n");
92 thread_stop();
93}
94
95module_init(prepare_to_wait_exclusive_init);
96module_exit(prepare_to_wait_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 prepare_to_wait_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 prepare_to_wait_exclusive
16463 ? 00:00:00 prepare_to_wait_exclusive wake_thread example
16464 ? 00:00:00 prepare_to_wait_exclusive 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
[ 7174.172701] inside kthread init function
[ 7174.172792] successfully created wake thread
[ 7174.172793] wake thread execution i value = 0
[ 7174.172859] successfully created wait thread
[ 7175.184158] wake thread execution i value = 1
[ 7175.184252] wait thread execution i value = 2
[ 7176.208146] wake thread execution i value = 2
[ 7176.208166] wait thread execution i value = 3
[ 7177.232125] wake thread execution i value = 3
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 prepare_to_wait_exclusive
test@test-V520-15IKL:~$
Check for kernel messages from exit function using dmesg command.
test@test-V520-15IKL:~$ sudo dmesg
[ 7184.655846] inside kthread exit function
[ 7186.447855] destroyed threads and completed tasks
In this example let’s see how to wait using prepare_to_wait_event.
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 prepare_to_wait_event");
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_thread;
DECLARE_WAIT_QUEUE_HEAD(wqueue);
struct wait_queue_entry 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 prepare_to_wait_event_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)
{
wake_thread = kthread_run(wake_thread_fn,NULL,"prepare_to_wait_event wake_thread example");
if (IS_ERR(wake_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
wait_thread = kthread_run(wait_thread_fn,NULL,"prepare_to_wait_event wait_thread example");
if(IS_ERR(wait_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 prepare_to_wait_event_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_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)
{
DEFINE_WAIT(wait);
while(!kthread_should_stop()) {
prepare_to_wait_event(&wqueue,&wait,TASK_INTERRUPTIBLE);
schedule();
pr_info("wait thread execution i value = %d\n",i);
msleep(1000);
}
finish_wait(&wqueue,&wait);
return 0;
}
int wake_thread_fn(void *data)
{
while(!kthread_should_stop()) {
pr_info("wake thread execution i value = %d\n",i);
i++;
msleep(1000);
}
return 0;
}
Add the driver entry points which will be executed once the module is inserted or removed from the kernel.
module_init(prepare_to_wait_event_init);
module_exit(prepare_to_wait_event_exit);
1#include <linux/module.h>
2#include <linux/init.h>
3#include <linux/kernel.h>
4#include <linux/kthread.h>
5#include <linux/delay.h>
6
7MODULE_LICENSE("GPL");
8MODULE_AUTHOR("linux usr");
9MODULE_DESCRIPTION("Example of prepare_to_wait_event");
10
11static struct task_struct *wait_thread;
12static struct task_struct *wake_thread;
13DECLARE_WAIT_QUEUE_HEAD(wqueue);
14struct wait_queue_entry wait;
15int i = 0;
16
17/* wait_thread_fn - executes when wait_thread is created,
18 * prints a message and sleeps for 1000ms,
19 * puts the wq_head in waiting state until wake_up signal is received,
20 * stops when kthread_stop is called */
21
22int wait_thread_fn(void *data)
23{
24 DEFINE_WAIT(wait);
25 while(!kthread_should_stop()) {
26 prepare_to_wait_event(&wqueue,&wait,TASK_INTERRUPTIBLE);
27 schedule();
28 pr_info("wait thread execution i value = %d\n",i);
29 msleep(1000);
30 }
31 finish_wait(&wqueue,&wait);
32 return 0;
33}
34
35/* wake_thread_fn - executes when wake_thread is created,
36 * prints a message, increments i value and sleeps for 1000ms,
37 * stops when kthread_stop is called */
38
39int wake_thread_fn(void *data)
40{
41 while(!kthread_should_stop()) {
42 pr_info("wake thread execution i value = %d\n",i);
43 i++;
44 msleep(1000);
45 }
46 return 0;
47}
48
49/* thread_start - creates thread and starts execution */
50
51void thread_start(void)
52{
53 wake_thread = kthread_run(wake_thread_fn,NULL,"prepare_to_wait_event wake_thread example");
54 if (IS_ERR(wake_thread))
55 pr_info("error in creating wake thread\n");
56 else
57 pr_info("successfully created wake thread\n");
58 wait_thread = kthread_run(wait_thread_fn,NULL,"prepare_to_wait_event wait_thread example");
59 if (IS_ERR(wait_thread))
60 pr_info("error in creating wait thread\n");
61 else
62 pr_info("successfully created wait thread\n");
63}
64
65/* prepare_to_wait_event_init - calls thread_start,
66 * executes when module is loaded */
67
68static int __init prepare_to_wait_event_init(void)
69{
70 pr_info("inside kthread init function\n");
71 thread_start();
72 return 0;
73}
74
75/* thread_stop - destroys thread and stops execution */
76
77void thread_stop(void)
78{
79 kthread_stop(wake_thread);
80 kthread_stop(wait_thread);
81 pr_info("destroyed threads and completed tasks\n");
82}
83
84/* prepare_to_wait_event_exit - calls thread_stop,
85 * executes when the module is unloaded */
86
87static void __exit prepare_to_wait_event_exit(void)
88{
89 pr_info("inside kthread exit function\n");
90 thread_stop();
91}
92
93module_init(prepare_to_wait_event_init);
94module_exit(prepare_to_wait_event_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 prepare_to_wait_event
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 prepare_to_wait_event
19802 ? 00:00:00 prepare_to_wait_event wake_thread example
19803 ? 00:00:00 prepare_to_wait_event 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
[ 9587.691360] inside kthread init function
[ 9587.691507] successfully created wake thread
[ 9587.691513] wake thread execution i value = 0
[ 9587.691677] successfully created wait thread
[ 9588.718682] wake thread execution i value = 1
[ 9589.742720] wake thread execution i value = 2
[ 9590.766771] wake thread execution i value = 3
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 prepare_to_wait_event
test@test-V520-15IKL:~$
Check for kernel messages from exit function using dmesg command.
test@test-V520-15IKL:~$ sudo dmesg
[ 9601.069175] inside kthread exit function
[ 9602.031027] wait thread execution i value = 14
[ 9603.055049] destroyed threads and completed tasks
In this example let’s see how to wait and wake up wait descriptor using wait_woken.
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 wait_woken");
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;
DECLARE_WAIT_QUEUE_HEAD(wqueue);
struct wait_queue_entry wait;
int i = 0;
Add the module init function which will be executed once we load the kernel module using insmod command.
static int __init wait_woken_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)
{
wake_thread = kthread_run(wake_thread_fn,NULL,"wait_woken wake_thread example");
if (IS_ERR(wake_thread))
pr_info("error creating thread\n");
else
pr_info("kthread created successfully\n");
wait_thread = kthread_run(wait_thread_fn,NULL,"wait_woken wait_thread example");
if(IS_ERR(wait_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 wait_woken_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_thread);
kthread_stop(wait_thread);
pr_info("destroyed threads and completed tasks\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)
{
DEFINE_WAIT(wait);
while(!kthread_should_stop()) {
wait_woken(&wait,TASK_UNINTERRUPTIBLE,msecs_to_jiffies(2000));
pr_info("wait thread execution i value = %d\n",i);
msleep(1000);
}
return 0;
}
int wake_thread_fn(void *data)
{
while(!kthread_should_stop()) {
pr_info("wake thread execution i value = %d\n",i);
i++;
msleep(1000);
}
return 0;
}
Add the driver entry points which will be executed once the module is inserted or removed from the kernel.
module_init(wait_woken_init);
module_exit(wait_woken_exit);
1#include <linux/module.h>
2#include <linux/init.h>
3#include <linux/kernel.h>
4#include <linux/kthread.h>
5#include <linux/delay.h>
6
7MODULE_LICENSE("GPL");
8MODULE_AUTHOR("linux usr");
9MODULE_DESCRIPTION("Example of wait_woken");
10
11static struct task_struct *wait_thread;
12static struct task_struct *wake_thread;
13DECLARE_WAIT_QUEUE_HEAD(wqueue);
14struct wait_queue_entry wait;
15int i = 0;
16
17/* wait_thread_fn - executes when wait_thread is created,
18 * prints a message and sleeps for 1000ms,
19 * puts in waiting state until timer gets expire,
20 * stops when kthread_stop is called */
21
22int wait_thread_fn(void *data)
23{
24 DEFINE_WAIT(wait);
25 while(!kthread_should_stop()) {
26 wait_woken(&wait,TASK_UNINTERRUPTIBLE,msecs_to_jiffies(2000));
27 pr_info("wait thread execution i value = %d\n",i);
28 msleep(1000);
29 }
30 return 0;
31}
32
33/* wake_thread_fn - executes when wake_thread is created,
34 * prints a message increments i and sleeps for 1000ms,
35 * stops when kthread_stop is called */
36
37int wake_thread_fn(void *data)
38{
39 while(!kthread_should_stop()) {
40 pr_info("wake thread execution i value = %d\n",i);
41 i++;
42 msleep(1000);
43 }
44 return 0;
45}
46
47/* thread_start - creates thread and starts execution */
48
49void thread_start(void)
50{
51 wake_thread = kthread_run(wake_thread_fn,NULL,"wait_woken wake_thread example");
52 if (IS_ERR(wake_thread))
53 pr_info("error in creating wake thread\n");
54 else
55 pr_info("successfully created wake thread\n");
56 wait_thread = kthread_run(wait_thread_fn,NULL,"wait_woken wait_thread example");
57 if (IS_ERR(wait_thread))
58 pr_info("error in creating wait thread\n");
59 else
60 pr_info("successfully created wait thread\n");
61}
62
63/* wait_woken_init - calls thread_start,
64 * executes when the module is loaded */
65
66static int __init wait_woken_init(void)
67{
68 pr_info("inside kthread init function\n");
69 thread_start();
70 return 0;
71}
72
73/* thread_stop - destroys thread and starts execution */
74
75void thread_stop(void)
76{
77 kthread_stop(wake_thread);
78 kthread_stop(wait_thread);
79 pr_info("destroyed threads and completed tasks\n");
80}
81
82/* wait_woken_exit - calls thread_stop,
83 * executes when the module is unloaded */
84
85static void __exit wait_woken_exit(void)
86{
87 pr_info("inside kthread exit function\n");
88 thread_stop();
89}
90
91module_init(wait_woken_init);
92module_exit(wait_woken_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 wait_woken
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 wait_woken
24197 ? 00:00:00 wait_woken wake_thread example
24198 ? 00:00:00 wait_woken 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
[12873.287079] inside kthread init function
[12873.287202] successfully created wake thread
[12873.287222] successfully created wait thread
[12873.287233] wake thread execution i value = 0
[12874.320890] wake thread execution i value = 1
[12875.312942] wait thread execution i value = 2
[12875.344928] wake thread execution i value = 2
[12876.368973] wake thread execution i value = 3
[12877.393097] wake thread execution i value = 4
[12878.353048] wait thread execution i value = 5
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 wait_woken
test@test-V520-15IKL:~$
Check for kernel messages from exit function using dmesg command.
test@test-V520-15IKL:~$ sudo dmesg
[12882.952350] inside kthread exit function
[12884.561252] destroyed threads and completed tasks
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 |
DEFINE_WAIT |
Declare waitqueue descriptor |
wait_event |
sleeps until the condition is true |
wait_event_timeout |
sleeps until the condition is true or timer gets expired |
prepare_to_wait |
sleeps until a wake_up signal is sent |
finish_wait |
clean up after waiting in a queue |
wake_up |
wake up the waiting waitqueues under wait_event APIs |
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 |