mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
kthread, timer
This commit is contained in:
19
README.md
19
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)
|
||||
|
||||
45
kernel_module/kthread.c
Normal file
45
kernel_module/kthread.c
Normal file
@@ -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 <linux/delay.h> /* usleep_range */
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -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 <linux/delay.h>
|
||||
#include <linux/delay.h> /* usleep_range */
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h> /* 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;
|
||||
|
||||
41
kernel_module/timer.c
Normal file
41
kernel_module/timer.c
Normal file
@@ -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 <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
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);
|
||||
}
|
||||
35
kernel_module/work_from_work.c
Normal file
35
kernel_module/work_from_work.c
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Declare more work from a workqueue.
|
||||
|
||||
TODO: kernel panic. Why?
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -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/
|
||||
|
||||
Reference in New Issue
Block a user