Skip to content

Commit 7d16a5c

Browse files
committed
Move sleep and workqueue module doc to README
sleep was broken because the workqueue was declared locally inside init, further evidence that no one has ever run the examples :-(
1 parent 0ccbc04 commit 7d16a5c

File tree

5 files changed

+87
-60
lines changed

5 files changed

+87
-60
lines changed

README.adoc

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1440,7 +1440,7 @@ does not give any interesting hits at `cc`, no symbol was placed that far.
14401440

14411441
==== GDB module_init
14421442

1443-
TODO find a convenient method. We have working methods, but they are not convenient.
1443+
TODO find a more convenient method. We have working methods, but they are not ideal.
14441444

14451445
This is not very easy, since by the time the module finishes loading, and `lx-symbols` can work properly, `module_init` has already finished running!
14461446

@@ -3993,6 +3993,8 @@ The count stops when we `rmmod`:
39933993
rmmod kthread
39943994
....
39953995

3996+
The sleep is done with `usleep_range`, see: <<sleep>>.
3997+
39963998
Bibliography:
39973999

39984000
* http://stackoverflow.com/questions/10177641/proper-way-of-handling-threads-in-kernel
@@ -4032,6 +4034,65 @@ Possible very likely outcome:
40324034

40334035
The threads almost always interleaved nicely, thus confirming that they are actually running in parallel.
40344036

4037+
===== sleep
4038+
4039+
Count to dmesg every one second from `0` up to `n - 1`:
4040+
4041+
....
4042+
insmod /sleep.ko n=5
4043+
....
4044+
4045+
Source: link:kernel_module/sleep.c[]
4046+
4047+
The sleep is done with a call to `usleep_range` directly inside `module_init` for simplicity.
4048+
4049+
Bibliography:
4050+
4051+
* https://stackoverflow.com/questions/15994603/how-to-sleep-in-the-linux-kernel/44153288#44153288
4052+
* https://github.com/torvalds/linux/blob/v4.17/Documentation/timers/timers-howto.txt
4053+
4054+
===== Workqueue
4055+
4056+
A more convenient front-end for <<kthread>>:
4057+
4058+
....
4059+
insmod /workqueue_cheat.ko
4060+
....
4061+
4062+
Outcome: count from `0` to `9` infinitely many times
4063+
4064+
Stop counting:
4065+
4066+
....
4067+
rmmod workqueue_cheat
4068+
....
4069+
4070+
Source: link:kernel_module/workqueue_cheat.c[]
4071+
4072+
The workqueue thread is killed after the worker function returns.
4073+
4074+
We can't call the module just `workqueue.c` because there is already a built-in with that name: https://unix.stackexchange.com/questions/364956/how-can-insmod-fail-with-kernel-module-is-already-loaded-even-is-lsmod-does-not
4075+
4076+
Bibliography: https://github.com/torvalds/linux/blob/v4.17/Documentation/core-api/workqueue.rst
4077+
4078+
===== Workqueue from workqueue
4079+
4080+
Count from `0` to `9` every second infinitely many times by scheduling a new work item from a work item:
4081+
4082+
....
4083+
insmod /work_from_work.ko
4084+
....
4085+
4086+
Stop:
4087+
4088+
....
4089+
rmmod work_from_work
4090+
....
4091+
4092+
The sleep is done indirectly through: `queue_delayed_work`, which waits the specified time before scheduling the work.
4093+
4094+
Source: link:kernel_module/work_from_work.c[]
4095+
40354096
===== schedule
40364097

40374098
Let's block the entire kernel! Yay:

kernel_module/README.adoc

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
https://github.com/cirosantilli/linux-kernel-module-cheat#directory-structure
22

33
. Asynchronous
4-
.. link:sleep.c[]
54
.. link:timer.c[]
6-
.. link:work_from_work.c[]
7-
.. link:workqueue_cheat.c[]

kernel_module/sleep.c

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,24 @@
1-
/*
2-
Usage:
3-
4-
insmod /sleep.ko
5-
rmmod sleep
6-
7-
dmesg prints an integer every second until rmmod.
8-
9-
Since insmod returns, this also illustrates how the work queues are asynchronous.
10-
*/
1+
/* https://github.com/cirosantilli/linux-kernel-module-cheat#sleep */
112

123
#include <linux/delay.h> /* usleep_range */
134
#include <linux/kernel.h>
145
#include <linux/module.h>
156
#include <linux/types.h> /* atomic_t */
16-
#include <linux/workqueue.h>
177

18-
static struct workqueue_struct *queue;
19-
static atomic_t run = ATOMIC_INIT(1);
8+
static u32 n = 5;
9+
module_param(n, int, S_IRUSR | S_IWUSR);
2010

21-
static void work_func(struct work_struct *work)
11+
static int myinit(void)
2212
{
23-
int i = 0;
24-
while (atomic_read(&run)) {
13+
u32 i;
14+
for (i = 0; i < n; ++i) {
2515
pr_info("%d\n", i);
2616
usleep_range(1000000, 1000001);
27-
i++;
28-
if (i == 10)
29-
i = 0;
3017
}
31-
}
32-
33-
static int myinit(void)
34-
{
35-
DECLARE_WORK(work, work_func);
36-
queue = create_workqueue("myworkqueue");
37-
queue_work(queue, &work);
3818
return 0;
3919
}
4020

41-
static void myexit(void)
42-
{
43-
atomic_set(&run, 0);
44-
destroy_workqueue(queue);
45-
}
21+
static void myexit(void) {}
4622

4723
module_init(myinit)
4824
module_exit(myexit)

kernel_module/work_from_work.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
/*
2-
Declare more work from a workqueue.
3-
*/
1+
/* https://github.com/cirosantilli/linux-kernel-module-cheat#workqueue-from-workqueue */
42

53
#include <linux/kernel.h>
64
#include <linux/module.h>
75
#include <linux/workqueue.h>
86

9-
static int i = 0;
7+
static int i;
108
static struct workqueue_struct *queue;
119

1210
static void work_func(struct work_struct *work);
@@ -18,6 +16,8 @@ static void work_func(struct work_struct *work)
1816
{
1917
pr_info("%d\n", i);
2018
i++;
19+
if (i == 10)
20+
i = 0;
2121
queue_delayed_work(queue, &next_work, HZ);
2222
}
2323

kernel_module/workqueue_cheat.c

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,38 @@
1-
/*
2-
Usage:
3-
4-
insmod /workqueue_cheat.ko
5-
# dmesg => worker
6-
rmmod workqueue_cheat
7-
8-
Creates a separate thread. So init_module can return, but some work will still get done.
9-
10-
Can't call this just workqueue.c because there is already a built-in with that name:
11-
https://unix.stackexchange.com/questions/364956/how-can-insmod-fail-with-kernel-module-is-already-loaded-even-is-lsmod-does-not
12-
13-
Workqueues are a convenience frontend for kthreads.
14-
15-
Bibliography:
16-
17-
- https://www.ibm.com/developerworks/library/l-tasklets/
18-
*/
1+
/* https://github.com/cirosantilli/linux-kernel-module-cheat#workqueue */
192

3+
#include <linux/delay.h> /* usleep_range */
204
#include <linux/kernel.h>
215
#include <linux/module.h>
6+
#include <linux/types.h> /* atomic_t */
227
#include <linux/workqueue.h>
238

249
static struct workqueue_struct *queue;
10+
static atomic_t run = ATOMIC_INIT(1);
2511

2612
static void work_func(struct work_struct *work)
2713
{
28-
pr_info("worker\n");
14+
int i = 0;
15+
while (atomic_read(&run)) {
16+
pr_info("%d\n", i);
17+
usleep_range(1000000, 1000001);
18+
i++;
19+
if (i == 10)
20+
i = 0;
21+
}
2922
}
3023

3124
DECLARE_WORK(work, work_func);
3225

3326
static int myinit(void)
3427
{
35-
queue = create_singlethread_workqueue("myworkqueue");
28+
queue = create_workqueue("myworkqueue");
3629
queue_work(queue, &work);
3730
return 0;
3831
}
3932

4033
static void myexit(void)
4134
{
42-
/* Waits for jobs to finish. */
35+
atomic_set(&run, 0);
4336
destroy_workqueue(queue);
4437
}
4538

0 commit comments

Comments
 (0)