Skip to content

Commit bf523b2

Browse files
Simplify code by removal of outer struct
Two struct completion(s) are encapsulated within another 'struct machine'. Simplify the code by removing the outer struct and let the struct completion(s) be self-standing. Update description in tex to match code.
1 parent c6b02ad commit bf523b2

File tree

2 files changed

+22
-21
lines changed

2 files changed

+22
-21
lines changed

examples/completions.c

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,32 @@
99
#include <linux/printk.h>
1010
#include <linux/version.h>
1111

12-
static struct {
13-
struct completion crank_comp;
14-
struct completion flywheel_comp;
15-
} machine;
12+
static struct completion crank_comp;
13+
static struct completion flywheel_comp;
1614

1715
static int machine_crank_thread(void *arg)
1816
{
1917
pr_info("Turn the crank\n");
2018

21-
complete_all(&machine.crank_comp);
19+
complete_all(&crank_comp);
2220
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
23-
kthread_complete_and_exit(&machine.crank_comp, 0);
21+
kthread_complete_and_exit(&crank_comp, 0);
2422
#else
25-
complete_and_exit(&machine.crank_comp, 0);
23+
complete_and_exit(&crank_comp, 0);
2624
#endif
2725
}
2826

2927
static int machine_flywheel_spinup_thread(void *arg)
3028
{
31-
wait_for_completion(&machine.crank_comp);
29+
wait_for_completion(&crank_comp);
3230

3331
pr_info("Flywheel spins up\n");
3432

35-
complete_all(&machine.flywheel_comp);
33+
complete_all(&flywheel_comp);
3634
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
37-
kthread_complete_and_exit(&machine.flywheel_comp, 0);
35+
kthread_complete_and_exit(&flywheel_comp, 0);
3836
#else
39-
complete_and_exit(&machine.flywheel_comp, 0);
37+
complete_and_exit(&flywheel_comp, 0);
4038
#endif
4139
}
4240

@@ -47,8 +45,8 @@ static int __init completions_init(void)
4745

4846
pr_info("completions example\n");
4947

50-
init_completion(&machine.crank_comp);
51-
init_completion(&machine.flywheel_comp);
48+
init_completion(&crank_comp);
49+
init_completion(&flywheel_comp);
5250

5351
crank_thread = kthread_create(machine_crank_thread, NULL, "KThread Crank");
5452
if (IS_ERR(crank_thread))
@@ -73,8 +71,8 @@ static int __init completions_init(void)
7371

7472
static void __exit completions_exit(void)
7573
{
76-
wait_for_completion(&machine.crank_comp);
77-
wait_for_completion(&machine.flywheel_comp);
74+
wait_for_completion(&crank_comp);
75+
wait_for_completion(&flywheel_comp);
7876

7977
pr_info("completions exit\n");
8078
}

lkmpg.tex

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,16 +1645,19 @@ \subsection{Completions}
16451645
Sometimes one thing should happen before another within a module having multiple threads.
16461646
Rather than using \sh|/bin/sleep| commands, the kernel has another way to do this which allows timeouts or interrupts to also happen.
16471647

1648-
In the following example two threads are started, but one needs to start before another.
1648+
Completions as code synchronization mechanism have three main parts, initialization of struct completion synchronization object, the waiting or barrier part through \cpp|wait_for_completion()|, and the signalling side through a call to \cpp|complete()|.
16491649

1650-
\samplec{examples/completions.c}
1651-
1652-
The \cpp|machine| structure stores the completion states for the two threads.
1650+
In the subsequent example, two threads are initiated: crank and flywheel.
1651+
It is imperative that the crank thread starts before the flywheel thread.
1652+
A completion state is established for each of these threads, with a distinct completion defined for both the crank and flywheel threads.
16531653
At the exit point of each thread the respective completion state is updated, and \cpp|wait_for_completion| is used by the flywheel thread to ensure that it does not begin prematurely.
1654+
The crank thread uses the \cpp|complete_all()| function to update the completion, which lets the flywheel thread continue.
16541655

1655-
So even though \cpp|flywheel_thread| is started first you should notice if you load this module and run \sh|dmesg| that turning the crank always happens first because the flywheel thread waits for it to complete.
1656+
So even though \cpp|flywheel_thread| is started first you should notice when you load this module and run \sh|dmesg|, that turning the crank always happens first because the flywheel thread waits for the crank thread to complete.
16561657

1657-
There are other variations upon the \cpp|wait_for_completion| function, which include timeouts or being interrupted, but this basic mechanism is enough for many common situations without adding a lot of complexity.
1658+
There are other variations of the \cpp|wait_for_completion| function, which include timeouts or being interrupted, but this basic mechanism is enough for many common situations without adding a lot of complexity.
1659+
1660+
\samplec{examples/completions.c}
16581661

16591662
\section{Avoiding Collisions and Deadlocks}
16601663
\label{sec:synchronization}

0 commit comments

Comments
 (0)