Skip to content

Commit 7f88a37

Browse files
authored
Merge pull request #234 from mechanicalamit/completions-simplify
Simplify code by removal of outer struct encapsulating struct completions
2 parents c6b02ad + bf523b2 commit 7f88a37

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)