Skip to content

Commit 258add9

Browse files
committed
wait queue: move docs to README
Do just one example with 2 waits, my readers can handle it :-)
1 parent f59ca5a commit 258add9

File tree

3 files changed

+87
-45
lines changed

3 files changed

+87
-45
lines changed

README.adoc

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4124,6 +4124,51 @@ The system also responds if we <<number-of-cores,add another core>>:
41244124
./run -c 2 -F 'dmesg -n 1;insmod /schedule.ko schedule=0'
41254125
....
41264126

4127+
==== Wait queues
4128+
4129+
Wait queues are a way to make a thread sleep until an event happens on the queue:
4130+
4131+
....
4132+
insmod /wait_queue.c
4133+
....
4134+
4135+
Dmesg output:
4136+
4137+
....
4138+
0 0
4139+
1 0
4140+
2 0
4141+
# Wait one second.
4142+
0 1
4143+
1 1
4144+
2 1
4145+
# Wait one second.
4146+
0 2
4147+
1 2
4148+
2 2
4149+
...
4150+
....
4151+
4152+
Stop the count:
4153+
4154+
....
4155+
rmmod wait_queue
4156+
....
4157+
4158+
Source: link:kernel_module/wait_queue.c[]
4159+
4160+
This example launches three threads:
4161+
4162+
* one thread generates events every with link:https://github.com/torvalds/linux/blob/v4.17/include/linux/wait.h#L195[`wake_up`]
4163+
* the other two threads wait for that with link:https://github.com/torvalds/linux/blob/v4.17/include/linux/wait.h#L286[`wait_event`], and print a dmesg when it happens.
4164+
+
4165+
The `wait_event` macro works a bit like:
4166+
+
4167+
....
4168+
while (!cond)
4169+
sleep_until_event
4170+
....
4171+
41274172
=== Timers
41284173

41294174
Count from `0` to `9` infinitely many times in 1 second intervals using timers:

kernel_module/wait_queue.c

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,74 @@
1-
/*
2-
"wait_event" works a bit like:
3-
4-
while (!cond)
5-
sleep_until_event
6-
7-
Outcome:
8-
9-
1 0
10-
2 0
11-
# Wait one second.
12-
1 1
13-
2 1
14-
# Wait one second.
15-
1 2
16-
2 2
17-
# ...
18-
*/
1+
/* https://github.com/cirosantilli/linux-kernel-module-cheat#wait-queues */
192

203
#include <linux/delay.h> /* usleep_range */
214
#include <linux/kernel.h>
225
#include <linux/kthread.h>
236
#include <linux/module.h>
247
#include <linux/wait.h> /* wait_queue_head_t, wait_event_interruptible, wake_up_interruptible */
258

26-
static struct task_struct *kthread1, *kthread2;
9+
static struct task_struct *kthread_wake;
10+
static struct task_struct *kthread_sleep1;
11+
static struct task_struct *kthread_sleep2;
2712
static wait_queue_head_t queue;
28-
static atomic_t awake = ATOMIC_INIT(0);
13+
static atomic_t awake1 = ATOMIC_INIT(0);
14+
static atomic_t awake2 = ATOMIC_INIT(0);
2915

30-
static int kthread_func1(void *data)
16+
static int kthread_wake_func(void *data)
3117
{
3218
unsigned int i = 0;
3319
while (!kthread_should_stop()) {
34-
pr_info("1 %u\n", i);
20+
pr_info("0 %u\n", i);
3521
usleep_range(1000000, 1000001);
36-
atomic_set(&awake, 1);
22+
atomic_set(&awake1, 1);
23+
atomic_set(&awake2, 1);
3724
wake_up(&queue);
3825
i++;
3926
}
4027
return 0;
4128
}
4229

43-
static int kthread_func2(void *data)
30+
static int kthread_sleep_func_1(void *data)
31+
{
32+
unsigned int i = 0;
33+
while (!kthread_should_stop()) {
34+
pr_info("1 %u\n", i);
35+
i++;
36+
wait_event(queue, atomic_read(&awake1));
37+
atomic_set(&awake1, 0);
38+
schedule();
39+
}
40+
return 0;
41+
}
42+
43+
static int kthread_sleep_func_2(void *data)
4444
{
4545
unsigned int i = 0;
4646
while (!kthread_should_stop()) {
4747
pr_info("2 %u\n", i);
4848
i++;
49-
wait_event(queue, atomic_read(&awake));
50-
atomic_set(&awake, 0);
49+
wait_event(queue, atomic_read(&awake2));
50+
atomic_set(&awake2, 0);
5151
schedule();
5252
}
5353
return 0;
5454
}
5555

56-
static int myinit(void)
56+
int init_module(void)
5757
{
5858
init_waitqueue_head(&queue);
59-
kthread1 = kthread_create(kthread_func1, NULL, "mykthread1");
60-
kthread2 = kthread_create(kthread_func2, NULL, "mykthread2");
61-
wake_up_process(kthread1);
62-
wake_up_process(kthread2);
59+
kthread_wake = kthread_create(kthread_wake_func, NULL, "wake");
60+
kthread_sleep1 = kthread_create(kthread_sleep_func_1, NULL, "sleep1");
61+
kthread_sleep2 = kthread_create(kthread_sleep_func_2, NULL, "sleep2");
62+
wake_up_process(kthread_wake);
63+
wake_up_process(kthread_sleep1);
64+
wake_up_process(kthread_sleep2);
6365
return 0;
6466
}
6567

66-
static void myexit(void)
68+
void cleanup_module(void)
6769
{
68-
/* 2 must be stopped before, or else we can deadlock. */
69-
kthread_stop(kthread2);
70-
kthread_stop(kthread1);
70+
kthread_stop(kthread_sleep2);
71+
kthread_stop(kthread_sleep1);
72+
kthread_stop(kthread_wake);
7173
}
72-
73-
module_init(myinit)
74-
module_exit(myexit)
7574
MODULE_LICENSE("GPL");

kernel_module/wait_queue2.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
/*
2-
Two threads waiting on a single event.
3-
*/
1+
/* https://github.com/cirosantilli/linux-kernel-module-cheat#wait-queues */
42

53
#include <linux/delay.h> /* usleep_range */
64
#include <linux/kernel.h>
@@ -29,7 +27,7 @@ static int kthread_wake_func(void *data)
2927
return 0;
3028
}
3129

32-
static int kthread_sleep1_func(void *data)
30+
static int kthread_sleep_func_1(void *data)
3331
{
3432
unsigned int i = 0;
3533
while (!kthread_should_stop()) {
@@ -42,7 +40,7 @@ static int kthread_sleep1_func(void *data)
4240
return 0;
4341
}
4442

45-
static int kthread_sleep2_func(void *data)
43+
static int kthread_sleep_func_2(void *data)
4644
{
4745
unsigned int i = 0;
4846
while (!kthread_should_stop()) {
@@ -59,8 +57,8 @@ int init_module(void)
5957
{
6058
init_waitqueue_head(&queue);
6159
kthread_wake = kthread_create(kthread_wake_func, NULL, "wake");
62-
kthread_sleep1 = kthread_create(kthread_sleep1_func, NULL, "sleep1");
63-
kthread_sleep2 = kthread_create(kthread_sleep2_func, NULL, "sleep2");
60+
kthread_sleep1 = kthread_create(kthread_sleep_func_1, NULL, "sleep1");
61+
kthread_sleep2 = kthread_create(kthread_sleep_func_2, NULL, "sleep2");
6462
wake_up_process(kthread_wake);
6563
wake_up_process(kthread_sleep1);
6664
wake_up_process(kthread_sleep2);

0 commit comments

Comments
 (0)