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/printk.h>
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
|
|
||||||
static struct {
|
static struct completion crank_comp;
|
||||||
struct completion crank_comp;
|
static struct completion flywheel_comp;
|
||||||
struct completion flywheel_comp;
|
|
||||||
} machine;
|
|
||||||
|
|
||||||
static int machine_crank_thread(void *arg)
|
static int machine_crank_thread(void *arg)
|
||||||
{
|
{
|
||||||
pr_info("Turn the crank\n");
|
pr_info("Turn the crank\n");
|
||||||
|
|
||||||
complete_all(&machine.crank_comp);
|
complete_all(&crank_comp);
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
|
#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
|
#else
|
||||||
complete_and_exit(&machine.crank_comp, 0);
|
complete_and_exit(&crank_comp, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int machine_flywheel_spinup_thread(void *arg)
|
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");
|
pr_info("Flywheel spins up\n");
|
||||||
|
|
||||||
complete_all(&machine.flywheel_comp);
|
complete_all(&flywheel_comp);
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
|
#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
|
#else
|
||||||
complete_and_exit(&machine.flywheel_comp, 0);
|
complete_and_exit(&flywheel_comp, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,8 +45,8 @@ static int __init completions_init(void)
|
|||||||
|
|
||||||
pr_info("completions example\n");
|
pr_info("completions example\n");
|
||||||
|
|
||||||
init_completion(&machine.crank_comp);
|
init_completion(&crank_comp);
|
||||||
init_completion(&machine.flywheel_comp);
|
init_completion(&flywheel_comp);
|
||||||
|
|
||||||
crank_thread = kthread_create(machine_crank_thread, NULL, "KThread Crank");
|
crank_thread = kthread_create(machine_crank_thread, NULL, "KThread Crank");
|
||||||
if (IS_ERR(crank_thread))
|
if (IS_ERR(crank_thread))
|
||||||
@ -73,8 +71,8 @@ ERROR_THREAD_1:
|
|||||||
|
|
||||||
static void __exit completions_exit(void)
|
static void __exit completions_exit(void)
|
||||||
{
|
{
|
||||||
wait_for_completion(&machine.crank_comp);
|
wait_for_completion(&crank_comp);
|
||||||
wait_for_completion(&machine.flywheel_comp);
|
wait_for_completion(&flywheel_comp);
|
||||||
|
|
||||||
pr_info("completions exit\n");
|
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.
|
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.
|
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}
|
\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}
|
\section{Avoiding Collisions and Deadlocks}
|
||||||
\label{sec:synchronization}
|
\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.
|
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