mirror of
https://github.com/sysprog21/lkmpg.git
synced 2025-02-21 20:03:10 +08:00
Merge pull request #234 from mechanicalamit/completions-simplify
Simplify code by removal of outer struct encapsulating struct completions
This commit is contained in:
commit
7f88a37f09
@ -9,34 +9,32 @@
|
||||
#include <linux/printk.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
static struct {
|
||||
struct completion crank_comp;
|
||||
struct completion flywheel_comp;
|
||||
} machine;
|
||||
static struct completion crank_comp;
|
||||
static struct completion flywheel_comp;
|
||||
|
||||
static int machine_crank_thread(void *arg)
|
||||
{
|
||||
pr_info("Turn the crank\n");
|
||||
|
||||
complete_all(&machine.crank_comp);
|
||||
complete_all(&crank_comp);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
|
||||
kthread_complete_and_exit(&machine.crank_comp, 0);
|
||||
kthread_complete_and_exit(&crank_comp, 0);
|
||||
#else
|
||||
complete_and_exit(&machine.crank_comp, 0);
|
||||
complete_and_exit(&crank_comp, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int machine_flywheel_spinup_thread(void *arg)
|
||||
{
|
||||
wait_for_completion(&machine.crank_comp);
|
||||
wait_for_completion(&crank_comp);
|
||||
|
||||
pr_info("Flywheel spins up\n");
|
||||
|
||||
complete_all(&machine.flywheel_comp);
|
||||
complete_all(&flywheel_comp);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
|
||||
kthread_complete_and_exit(&machine.flywheel_comp, 0);
|
||||
kthread_complete_and_exit(&flywheel_comp, 0);
|
||||
#else
|
||||
complete_and_exit(&machine.flywheel_comp, 0);
|
||||
complete_and_exit(&flywheel_comp, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -47,8 +45,8 @@ static int __init completions_init(void)
|
||||
|
||||
pr_info("completions example\n");
|
||||
|
||||
init_completion(&machine.crank_comp);
|
||||
init_completion(&machine.flywheel_comp);
|
||||
init_completion(&crank_comp);
|
||||
init_completion(&flywheel_comp);
|
||||
|
||||
crank_thread = kthread_create(machine_crank_thread, NULL, "KThread Crank");
|
||||
if (IS_ERR(crank_thread))
|
||||
@ -73,8 +71,8 @@ ERROR_THREAD_1:
|
||||
|
||||
static void __exit completions_exit(void)
|
||||
{
|
||||
wait_for_completion(&machine.crank_comp);
|
||||
wait_for_completion(&machine.flywheel_comp);
|
||||
wait_for_completion(&crank_comp);
|
||||
wait_for_completion(&flywheel_comp);
|
||||
|
||||
pr_info("completions exit\n");
|
||||
}
|
||||
|
19
lkmpg.tex
19
lkmpg.tex
@ -1645,17 +1645,20 @@ $
|
||||
Sometimes one thing should happen before another within a module having multiple threads.
|
||||
Rather than using \sh|/bin/sleep| commands, the kernel has another way to do this which allows timeouts or interrupts to also happen.
|
||||
|
||||
In the following example two threads are started, but one needs to start before another.
|
||||
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()|.
|
||||
|
||||
In the subsequent example, two threads are initiated: crank and flywheel.
|
||||
It is imperative that the crank thread starts before the flywheel thread.
|
||||
A completion state is established for each of these threads, with a distinct completion defined for both the crank and flywheel threads.
|
||||
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.
|
||||
The crank thread uses the \cpp|complete_all()| function to update the completion, which lets the flywheel thread continue.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
\samplec{examples/completions.c}
|
||||
|
||||
The \cpp|machine| structure stores the completion states for the two threads.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
\section{Avoiding Collisions and Deadlocks}
|
||||
\label{sec:synchronization}
|
||||
If processes running on different CPUs or in different threads try to access the same memory, then it is possible that strange things can happen or your system can lock up.
|
||||
|
Loading…
x
Reference in New Issue
Block a user