From 258add9c9d5479f8ece2bc880541a4802d949153 Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Sun, 8 Jul 2018 09:58:05 +0100 Subject: [PATCH] wait queue: move docs to README Do just one example with 2 waits, my readers can handle it :-) --- README.adoc | 45 ++++++++++++++++++++++ kernel_module/wait_queue.c | 77 ++++++++++++++++++------------------- kernel_module/wait_queue2.c | 12 +++--- 3 files changed, 88 insertions(+), 46 deletions(-) diff --git a/README.adoc b/README.adoc index fc0bb62..54a86cc 100644 --- a/README.adoc +++ b/README.adoc @@ -4124,6 +4124,51 @@ The system also responds if we <>: ./run -c 2 -F 'dmesg -n 1;insmod /schedule.ko schedule=0' .... +==== Wait queues + +Wait queues are a way to make a thread sleep until an event happens on the queue: + +.... +insmod /wait_queue.c +.... + +Dmesg output: + +.... +0 0 +1 0 +2 0 +# Wait one second. +0 1 +1 1 +2 1 +# Wait one second. +0 2 +1 2 +2 2 +... +.... + +Stop the count: + +.... +rmmod wait_queue +.... + +Source: link:kernel_module/wait_queue.c[] + +This example launches three threads: + +* one thread generates events every with link:https://github.com/torvalds/linux/blob/v4.17/include/linux/wait.h#L195[`wake_up`] +* the other two threads wait for that with link:https://github.com/torvalds/linux/blob/v4.17/include/linux/wait.h#L286[`wait_event`], and print a dmesg when it happens. ++ +The `wait_event` macro works a bit like: ++ +.... +while (!cond) + sleep_until_event +.... + === Timers Count from `0` to `9` infinitely many times in 1 second intervals using timers: diff --git a/kernel_module/wait_queue.c b/kernel_module/wait_queue.c index 0a348f4..bb7d2d2 100644 --- a/kernel_module/wait_queue.c +++ b/kernel_module/wait_queue.c @@ -1,21 +1,4 @@ -/* -"wait_event" works a bit like: - - while (!cond) - sleep_until_event - -Outcome: - - 1 0 - 2 0 - # Wait one second. - 1 1 - 2 1 - # Wait one second. - 1 2 - 2 2 - # ... -*/ +/* https://github.com/cirosantilli/linux-kernel-module-cheat#wait-queues */ #include /* usleep_range */ #include @@ -23,53 +6,69 @@ Outcome: #include #include /* wait_queue_head_t, wait_event_interruptible, wake_up_interruptible */ -static struct task_struct *kthread1, *kthread2; +static struct task_struct *kthread_wake; +static struct task_struct *kthread_sleep1; +static struct task_struct *kthread_sleep2; static wait_queue_head_t queue; -static atomic_t awake = ATOMIC_INIT(0); +static atomic_t awake1 = ATOMIC_INIT(0); +static atomic_t awake2 = ATOMIC_INIT(0); -static int kthread_func1(void *data) +static int kthread_wake_func(void *data) { unsigned int i = 0; while (!kthread_should_stop()) { - pr_info("1 %u\n", i); + pr_info("0 %u\n", i); usleep_range(1000000, 1000001); - atomic_set(&awake, 1); + atomic_set(&awake1, 1); + atomic_set(&awake2, 1); wake_up(&queue); i++; } return 0; } -static int kthread_func2(void *data) +static int kthread_sleep_func_1(void *data) { unsigned int i = 0; while (!kthread_should_stop()) { - pr_info("2 %u\n", i); + pr_info("1 %u\n", i); i++; - wait_event(queue, atomic_read(&awake)); - atomic_set(&awake, 0); + wait_event(queue, atomic_read(&awake1)); + atomic_set(&awake1, 0); schedule(); } return 0; } -static int myinit(void) +static int kthread_sleep_func_2(void *data) { - init_waitqueue_head(&queue); - kthread1 = kthread_create(kthread_func1, NULL, "mykthread1"); - kthread2 = kthread_create(kthread_func2, NULL, "mykthread2"); - wake_up_process(kthread1); - wake_up_process(kthread2); + unsigned int i = 0; + while (!kthread_should_stop()) { + pr_info("2 %u\n", i); + i++; + wait_event(queue, atomic_read(&awake2)); + atomic_set(&awake2, 0); + schedule(); + } return 0; } -static void myexit(void) +int init_module(void) { - /* 2 must be stopped before, or else we can deadlock. */ - kthread_stop(kthread2); - kthread_stop(kthread1); + init_waitqueue_head(&queue); + kthread_wake = kthread_create(kthread_wake_func, NULL, "wake"); + kthread_sleep1 = kthread_create(kthread_sleep_func_1, NULL, "sleep1"); + kthread_sleep2 = kthread_create(kthread_sleep_func_2, NULL, "sleep2"); + wake_up_process(kthread_wake); + wake_up_process(kthread_sleep1); + wake_up_process(kthread_sleep2); + return 0; } -module_init(myinit) -module_exit(myexit) +void cleanup_module(void) +{ + kthread_stop(kthread_sleep2); + kthread_stop(kthread_sleep1); + kthread_stop(kthread_wake); +} MODULE_LICENSE("GPL"); diff --git a/kernel_module/wait_queue2.c b/kernel_module/wait_queue2.c index ab3e4df..bb7d2d2 100644 --- a/kernel_module/wait_queue2.c +++ b/kernel_module/wait_queue2.c @@ -1,6 +1,4 @@ -/* -Two threads waiting on a single event. -*/ +/* https://github.com/cirosantilli/linux-kernel-module-cheat#wait-queues */ #include /* usleep_range */ #include @@ -29,7 +27,7 @@ static int kthread_wake_func(void *data) return 0; } -static int kthread_sleep1_func(void *data) +static int kthread_sleep_func_1(void *data) { unsigned int i = 0; while (!kthread_should_stop()) { @@ -42,7 +40,7 @@ static int kthread_sleep1_func(void *data) return 0; } -static int kthread_sleep2_func(void *data) +static int kthread_sleep_func_2(void *data) { unsigned int i = 0; while (!kthread_should_stop()) { @@ -59,8 +57,8 @@ int init_module(void) { init_waitqueue_head(&queue); kthread_wake = kthread_create(kthread_wake_func, NULL, "wake"); - kthread_sleep1 = kthread_create(kthread_sleep1_func, NULL, "sleep1"); - kthread_sleep2 = kthread_create(kthread_sleep2_func, NULL, "sleep2"); + kthread_sleep1 = kthread_create(kthread_sleep_func_1, NULL, "sleep1"); + kthread_sleep2 = kthread_create(kthread_sleep_func_2, NULL, "sleep2"); wake_up_process(kthread_wake); wake_up_process(kthread_sleep1); wake_up_process(kthread_sleep2);