From 709d01e5137547fe679ec32e7ab46a844d7e1058 Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Mon, 5 Jun 2017 14:53:00 +0100 Subject: [PATCH] waitqueue example works, kthread_uniterruptible completely wrong and renamed to schedule, params added --- README.md | 3 +- kernel_module/kthread_uninterruptible.c | 38 ---------------- kernel_module/params.c | 51 ++++++++++++++++++++++ kernel_module/schedule.c | 58 +++++++++++++++++++++++++ kernel_module/wait_queue.c | 30 ++++++------- 5 files changed, 125 insertions(+), 55 deletions(-) delete mode 100644 kernel_module/kthread_uninterruptible.c create mode 100644 kernel_module/params.c create mode 100644 kernel_module/schedule.c diff --git a/README.md b/README.md index aeb23e6..f4275c9 100644 --- a/README.md +++ b/README.md @@ -309,6 +309,7 @@ But TODO I don't think you can see where you are in the kernel source code and l 1. [hello2](kernel_module/hello2.c) 1. [debugfs](kernel_module/debugfs.c) 1. [panic](kernel_module/panic.c) + 1. [params](kernel_module/params.c) 1. [fops](kernel_module/fops.c) 1. [poll](poll.c) 1. Asynchronous @@ -316,7 +317,7 @@ But TODO I don't think you can see where you are in the kernel source code and l 1. [sleep](kernel_module/sleep.c) 1. [kthread](kernel_module/kthread.c) 1. [kthreads](kernel_module/kthreads.c) - 1. [kthread_uninterruptible](kernel_module/kthread_uninterruptible.c) + 1. [schedule](kernel_module/schedule.c) 1. [timer](kernel_module/timer.c) 1. [work_from_work](kernel_module/work_from_work.c) 1. [irq](irq.c) diff --git a/kernel_module/kthread_uninterruptible.c b/kernel_module/kthread_uninterruptible.c deleted file mode 100644 index 0716cc8..0000000 --- a/kernel_module/kthread_uninterruptible.c +++ /dev/null @@ -1,38 +0,0 @@ -/* -Let's block the entire kernel! Yay! - -Also try after dmesg -n 1 to become convinced of the full blockage. -*/ - -#include -#include -#include - -MODULE_LICENSE("GPL"); - -static struct task_struct *kthread; - -static int work_func(void *data) -{ - set_current_state(TASK_UNINTERRUPTIBLE); - int i = 0; - while (!kthread_should_stop()) { - printk(KERN_INFO "%d\n", i); - i++; - if (i == 10) - i = 0; - } - return 0; -} - -int init_module(void) -{ - kthread = kthread_create(work_func, NULL, "mykthread"); - wake_up_process(kthread); - return 0; -} - -void cleanup_module(void) -{ - kthread_stop(kthread); -} diff --git a/kernel_module/params.c b/kernel_module/params.c new file mode 100644 index 0000000..90913cf --- /dev/null +++ b/kernel_module/params.c @@ -0,0 +1,51 @@ +/* +Allows passing parameters at insertion time. + +Those parameters can also be read and modified at runtime from /sys. + + insmod /params.ko + # dmesg => 0 + cd /sys/module/params/parameters + cat i + # => 0 + printf 1 >i + # dmesg => 1 + rmmod params + insmod /params.ko i=1 + # dmesg => 1 +*/ + +#include /* usleep_range */ +#include +#include +#include +#include /* S_IRUSR | S_IWUSR */ + +MODULE_LICENSE("GPL"); + +static int i = 0; +module_param(i, int, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(i, "my favorite int"); + +static struct task_struct *kthread; + +static int work_func(void *data) +{ + while (!kthread_should_stop()) { + pr_info("%d\n", i); + usleep_range(1000000, 1000001); + } + return 0; +} + +int init_module(void) +{ + kthread = kthread_create(work_func, NULL, "mykthread"); + wake_up_process(kthread); + return 0; +} + +void cleanup_module(void) +{ + kthread_stop(kthread); +} diff --git a/kernel_module/schedule.c b/kernel_module/schedule.c new file mode 100644 index 0000000..14332f4 --- /dev/null +++ b/kernel_module/schedule.c @@ -0,0 +1,58 @@ +/* +Let's block the entire kernel! Yay! + +kthreads only allow interrupting if you call schedule. + +If you don't, they just run forever, and you have to kill the VM. + +Test with: + + dmesg -n 1 + insmod /schedule.ko yn=[01] + dmesg | tail + +Then: + +- yn=0: + - `qemu -smp 1`: everything blocks! + - `qemu -smp 2`: you can still use the board, but is it noticeably slow +- yn=1: all good +*/ + +#include /* usleep_range */ +#include +#include +#include +#include /* S_IRUSR | S_IWUSR */ + +MODULE_LICENSE("GPL"); + +static int yn = 1; +module_param(yn, int, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(yn, "A short integer"); + +static struct task_struct *kthread; + +static int work_func(void *data) +{ + unsigned int i = 0; + while (!kthread_should_stop()) { + pr_info("%u\n", i); + i++; + if (yn) + schedule(); + } + return 0; +} + +int init_module(void) +{ + kthread = kthread_create(work_func, NULL, "mykthread"); + wake_up_process(kthread); + return 0; +} + +void cleanup_module(void) +{ + kthread_stop(kthread); +} diff --git a/kernel_module/wait_queue.c b/kernel_module/wait_queue.c index 9e1f992..b257457 100644 --- a/kernel_module/wait_queue.c +++ b/kernel_module/wait_queue.c @@ -1,5 +1,8 @@ /* -TODO get working. Thread 2 only wakes up once! Wake thread 2 up every 2 seconds from thread 1. +"wait_event" works a bit like: + + if (!cond) + sleep_until_event */ #include /* usleep_range */ @@ -12,20 +15,17 @@ MODULE_LICENSE("GPL"); static struct task_struct *kthread1, *kthread2; static wait_queue_head_t queue; -static int awake = 0; +static atomic_t awake = ATOMIC_INIT(0); static int kthread_func1(void *data) { - int i = 0; + unsigned int i = 0; while (!kthread_should_stop()) { - awake = !awake; - pr_info("1 %d\n", i); - wake_up_interruptible(&queue); - schedule(); + pr_info("1 %u\n", i); usleep_range(1000000, 1000001); + atomic_set(&awake, 1); + wake_up(&queue); i++; - if (i == 10) - i = 0; } i = !i; wake_up_interruptible(&queue); @@ -35,15 +35,13 @@ static int kthread_func1(void *data) static int kthread_func2(void *data) { set_current_state(TASK_INTERRUPTIBLE); - int i = 0; + unsigned int i = 0; while (!kthread_should_stop()) { - wait_event(queue, awake); - pr_info("2 %d\n", i); - set_current_state(TASK_INTERRUPTIBLE); - schedule(); + pr_info("2 %u\n", i); i++; - if (i == 10) - i = 0; + wait_event(queue, atomic_read(&awake)); + atomic_set(&awake, 0); + schedule(); } return 0; }