前言
这个 主要是 最开始的时候了解驱动的时候, 看到的一系列的 case, 这里 来大致剖析一下 相关的道理
这些模块 是怎么和内核交互的, 内核的这些业务是怎么实现的
这里主要是一个模块创建了一个 kthread 的线程, 然后 执行目标函数
然后这里主要是设计了 模块来调用 linux 的相关系统函数, 以及 kthread 的相关知识
测试用例
测试模块如下, 模块主要是来自于 某git仓库, 这里未记录信息, 感谢原作者
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/rwlock.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/delay.h>
struct task_struct *my_task;
static int k_thread_cycle_count = 0;
static int mykthread(void *unused)
{
for (;;) {
pr_info("mykthread is living!, count: %d\n", k_thread_cycle_count);
ssleep(3);
k_thread_cycle_count++;
// if(k_thread_cycle_count > 5)
// kthread_stop(my_task);
}
return 0;
}
static int __init k_thread_init(void)
{
my_task = kthread_run(mykthread, NULL,
"mykthread");
if (my_task == ERR_PTR(-ENOMEM)) {
printk(KERN_INFO " mykthread creation failed\n");
my_task = NULL;
return -ENOMEM;
}
return 0;
}
module_init(k_thread_init);
static void __exit k_thread_exit(void)
{
kthread_stop(my_task);
printk(KERN_INFO "k_thread exit\n ");
}
module_exit(k_thread_exit);
MODULE_AUTHOR("e665106");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("A simple k-thread Module");
MODULE_ALIAS("a simplest module");
kthreadd, kworker 的初始化
kthreadd 的进程如下
(initramfs) ps -l | grep kthread
S 0 2 0 0 0 0:0 16:55 00:00:00 [kthreadd]
S 0 250 246 4676 680 0:0 16:57 00:00:00 {exe} grep kthread
kthreadd 的初始化如下, 设置了 执行程序名称
然后就是处理 kthreadd 的相关业务
kthreadd 的主要工作主要是创建相关 kernel_thread
比如我们下面的 kworker 就属于 kthread, 这里我们可以看见的是 这里是在创建一个 kworker 它的执行函数是 worker_thread, 它的进程号是 3
kworker 列表如下
(initramfs) ps -l | grep work
# cpu_worker_pools[HIPRI_NICE]
S 0 4 2 0 0 0:0 14:35 00:00:00 [kworker/0:0H]
S 0 138 2 0 0 0:0 14:36 00:00:00 [kworker/0:1H]
# cpu_worker_pools[STD_NICE]
S 0 289 2 0 0 0:0 14:45 00:00:00 [kworker/0:0]
S 0 29 2 0 0 0:0 14:35 00:00:00 [kworker/0:1]
S 0 295 2 0 0 0:0 15:08 00:00:00 [kworker/0:2]
# unbound_pools[NUMA_NO_NODE]
S 0 5 2 0 0 0:0 14:35 00:00:00 [kworker/u2:0]
S 0 66 2 0 0 0:0 14:36 00:00:00 [kworker/u2:2]
kthread 的初始化主要是在这里
假设我这里 只有一个 cpu
这里 for_each_cpu_worker_pool 中循环了两个 pool, 一个是标准优先级的, 一个是高优先级的, 指定 0号 cpu 执行
hash_for_each 主要是初始化其他的 pool, 这里默认会创建一个 pool 在任意 cpu 执行
对应的进程的名称规则如下
前两个 pool 是指定 cpu#0, 因此名称是 ”0:0H” 或者 ”0:0”
后面一个 pool 是任意 cpu 执行, pool 的 id 为 2, 因此名称是 “u2:0”
my_kthread 进程的创建
thread_run 宏定义如下, 调用了 kthread_create 来创建进程
这里将需要创建的信息放入 thread_create_list, 具体的创建进程是交给 kthreadd
这里会 唤醒 kthreadd 干活, 然后 等待 进程创建成功
然后 开始调度 新建的 my_kthread 进程
然后 这里是 my_kthread 中输出 “mykthread is living!, count” 的相关信息
可以看到 上层函数基本上是在 传入的 threadfin 的函数片段中
然后 执行完成之后, my_kthread 对应的进程就完成任务了
查看创建的 my_kthread
(initramfs) ps -l | grep kthread
[ 89.312961] mykthread is living!, count: 5
S 0 2 0 0 0 0:0 17:51 00:00:00 [kthreadd]
D 0 261 2 0 0 0:0 17:53 00:00:00 [mykthread]
R 0 263 247 4676 700 0:0 17:53 00:00:00 {exe} grep kthread
(initramfs) [ 92.384636] mykthread is living!, count: 6
完