From f367ffc6cfafb07c8e10a8a2740f3133a7bea765 Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Tue, 16 May 2017 09:26:08 +0100 Subject: [PATCH] kthread, timer --- README.md | 19 +++++++++----- kernel_module/kthread.c | 45 +++++++++++++++++++++++++++++++++ kernel_module/sleep.c | 5 ++-- kernel_module/timer.c | 41 ++++++++++++++++++++++++++++++ kernel_module/work_from_work.c | 35 +++++++++++++++++++++++++ kernel_module/workqueue_cheat.c | 2 ++ 6 files changed, 137 insertions(+), 10 deletions(-) create mode 100644 kernel_module/kthread.c create mode 100644 kernel_module/timer.c create mode 100644 kernel_module/work_from_work.c diff --git a/README.md b/README.md index d6033e8..a439c4f 100644 --- a/README.md +++ b/README.md @@ -42,10 +42,15 @@ Then if you want your terminal back, hit `Ctrl + C, A` and type `quit`. See also 1. Examples 1. [Host](host/) 1. Buildroot - 1. [hello](kernel_module/hello.c) - 1. [hello2](kernel_module/hello2.c) - 1. [debugfs](kernel_module/debugfs.c) - 1. [fops](kernel_module/fops.c) - 1. [workqueue](kernel_module/workqueue.c) - 1. [panic](kernel_module/panic.c) - 1. [delay](kernel_module/delay.c) + 1. Debugging + 1. [hello](kernel_module/hello.c) + 1. [hello2](kernel_module/hello2.c) + 1. [debugfs](kernel_module/debugfs.c) + 1. [panic](kernel_module/panic.c) + 1. [fops](kernel_module/fops.c) + 1. Asynchronous + 1. [workqueue](kernel_module/workqueue.c) + 1. [sleep](kernel_module/sleep.c) + 1. [kthread](kernel_module/kthread.c) + 1. [timer](kernel_module/timer.c) + 1. [work_from_work](kernel_module/work_from_work.c) diff --git a/kernel_module/kthread.c b/kernel_module/kthread.c new file mode 100644 index 0000000..7e0d796 --- /dev/null +++ b/kernel_module/kthread.c @@ -0,0 +1,45 @@ +/* +Kernel threads are managed exactly like userland threads. + +They also have a backing task_struct, and are scheduled with the same mechanism. + +See also: + +- http://stackoverflow.com/questions/10177641/proper-way-of-handling-threads-in-kernel +- http://stackoverflow.com/questions/4084708/how-to-wait-for-a-linux-kernel-thread-kthreadto-exit +*/ + +#include /* usleep_range */ +#include +#include +#include + +MODULE_LICENSE("GPL"); + +static struct task_struct *kthread; + +static int work_func(void *data) +{ + int i = 0; + while (!kthread_should_stop()) { + printk(KERN_INFO "%d\n", i); + usleep_range(1000000, 1000001); + 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) +{ + /* Waits for thread to return. */ + kthread_stop(kthread); +} diff --git a/kernel_module/sleep.c b/kernel_module/sleep.c index 4587004..ef359a7 100644 --- a/kernel_module/sleep.c +++ b/kernel_module/sleep.c @@ -9,7 +9,7 @@ dmesg prints an integer every second until rmmod. Since insmod returns, this also illustrates how the work queues are asynchronous. */ -#include +#include /* usleep_range */ #include #include #include /* atomic_t */ @@ -32,10 +32,9 @@ static void work_func(struct work_struct *work) } } -DECLARE_WORK(work, work_func); - int init_module(void) { + DECLARE_WORK(work, work_func); queue = create_workqueue("myworkqueue"); queue_work(queue, &work); return 0; diff --git a/kernel_module/timer.c b/kernel_module/timer.c new file mode 100644 index 0000000..15c46ae --- /dev/null +++ b/kernel_module/timer.c @@ -0,0 +1,41 @@ +/* +Timers are callbacks that run when an interrupt happens, from the interrupt context itself. + +Therefore they produce more accurate timing than thread scheduling, which is more complex, +but you can't do too much work inside of them. + +See also: + +- http://stackoverflow.com/questions/10812858/timers-in-linux-device-drivers +- https://gist.github.com/yagihiro/310149 +*/ + +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +static void callback(unsigned long data); +static unsigned long onesec; + +DEFINE_TIMER(mytimer, callback, 0, 0); + +static void callback(unsigned long data) +{ + pr_info("%u\n", (unsigned)jiffies); + mod_timer(&mytimer, jiffies + onesec); +} + +int init_module(void) +{ + onesec = msecs_to_jiffies(1000); + mod_timer(&mytimer, jiffies + onesec); + return 0; +} + +void cleanup_module(void) +{ + del_timer(&mytimer); +} diff --git a/kernel_module/work_from_work.c b/kernel_module/work_from_work.c new file mode 100644 index 0000000..f017da2 --- /dev/null +++ b/kernel_module/work_from_work.c @@ -0,0 +1,35 @@ +/* +Declare more work from a workqueue. + +TODO: kernel panic. Why? +*/ + +#include +#include +#include + +MODULE_LICENSE("GPL"); + +static int i = 0; +static struct workqueue_struct *queue; + +static void work_func(struct work_struct *work) +{ + DECLARE_DELAYED_WORK(next_work, work_func); + printk(KERN_INFO "%d\n", i); + i++; + queue_delayed_work(queue, &next_work, HZ); +} + +int init_module(void) +{ + DECLARE_WORK(work, work_func); + queue = create_workqueue("myworkqueue"); + queue_work(queue, &work); + return 0; +} + +void cleanup_module(void) +{ + destroy_workqueue(queue); +} diff --git a/kernel_module/workqueue_cheat.c b/kernel_module/workqueue_cheat.c index 614249e..59f8f06 100644 --- a/kernel_module/workqueue_cheat.c +++ b/kernel_module/workqueue_cheat.c @@ -10,6 +10,8 @@ Creates a separate thread. So init_module can return, but some work will still g Can't call this just workqueue.c because there is already a built-in with that name: https://unix.stackexchange.com/questions/364956/how-can-insmod-fail-with-kernel-module-is-already-loaded-even-is-lsmod-does-not +Workqueues are a convenience frontend for kthreads. + Bibliography: - https://www.ibm.com/developerworks/library/l-tasklets/