当前位置: 首页 > news >正文

Linux rest_init kernel_init与kthreadd启动

Linux rest_init kernel_init与kthreadd启动

rest_init是start_kernel的最后一步,定义在init/main.c中。它在所有内核子系统初始化完成后被调用,负责创建两个最关键的内核线程——kernel_init(1号进程)和kthreadd(2号进程),然后将当前CPU控制权交给idle循环。

函数实现如下:

```c
// init/main.c
static noinline void __init __noreturn rest_init(void)
{
struct task_struct *tsk;
int pid;

// 第一步: 使用kernel_thread创建kernel_init(1号进程)
// kernel_init负责启动用户空间的init程序
pid = kernel_thread(kernel_init, NULL,
CLONE_FS | CLONE_FILES |
CLONE_SIGHAND | CLONE_THREAD);
rcu_assign_pointer(kernel_init_task,
find_task_by_vpid(pid));

// 第二步: 使用kernel_thread创建kthreadd(2号进程)
// kthreadd是所有内核线程的父进程
pid = kernel_thread(kthreadd, NULL,
CLONE_FS | CLONE_FILES |
CLONE_SIGHAND);
rcu_assign_pointer(kthreadd_task,
find_task_by_vpid(pid));

// 第三步: 将boot CPU的idle进程关联到current
// 此时current即init_task
// 通过PF_IDLE标志标识idle线程
current->flags |= PF_IDLE;

// 第四步: 初始化pid_ns中的init进程组
// 使kernel_init成为PID namespace的1号进程
init_pid_ns.child_reaper = current;

// 第五步: 解锁所有在start_kernel期间被锁定的子系统
// 允许kernel_init和kthreadd开始执行
smp_mb();
complete(&kthreadd_done);
complete(&init_done);

// 第六步: 进入idle循环
// 至此,CPU0变为idle线程
cpu_startup_entry(CPUHP_ONLINE);
}
```

kernel_init的执行路径决定了整个用户空间如何启动。它在得到调度后执行以下步骤:

```c
// init/main.c
static int __ref kernel_init(void *unused)
{
int ret;

// 等待kthreadd完全初始化
wait_for_completion(&kthreadd_done);

// 初始化ramdisk/initramfs
// 如果内核被编译为内嵌initramfs,在此展开
if (ramdisk_execute_command) {
ret = run_init_process(ramdisk_execute_command);
if (!ret)
return 0;
pr_err("Failed to execute %s\n",
ramdisk_execute_command);
}

// 尝试依次执行多个可能的init程序路径
// 按照优先级从高到低尝试
if (execute_command) {
// 如果cmdline指定了init=,使用该路径
ret = run_init_process(execute_command);
if (!ret)
return 0;
panic("Requested init %s failed (error %d).",
execute_command, ret);
}

// 默认路径搜索顺序
if (!try_to_run_init_process("/sbin/init") ||
!try_to_run_init_process("/etc/init") ||
!try_to_run_init_process("/bin/init") ||
!try_to_run_init_process("/bin/sh"))
return 0;

// 所有init路径都失败,内核panic
panic("No working init found. Try passing init= option "
"to kernel. See Linux Documentation/admin-guide/"
"init.rst for guidance.");
}

// run_init_process是exec系统调用的封装
static int __ref run_init_process(const char *init_filename)
{
// 使用kernel_execve加载并执行init程序
// argv和envp是标准的内核init参数
char *argv[] = { init_filename, NULL };
char *envp[] = { "HOME=/",
"TERM=linux",
NULL };

pr_info("Run %s as init process\n", init_filename);
return kernel_execve(init_filename, argv, envp);
}
```

kthreadd是内核线程的守护进程,所有通过kthread_create创建的内核线程都是由kthreadd通过fork生成的:

```c
// kernel/kthread.c
int kthreadd(void *unused)
{
struct task_struct *tsk;

// 设置内存回收标志
tsk = current;
tsk->flags |= PF_NOFREEZE;

// 通知kernel_init kthreadd已就绪
complete(&kthreadd_done);

// 设置kthreadd的nice值,使其以较高优先级运行
set_user_nice(tsk, -5);

// 主循环: 处理kthread创建请求
for (;;) {
// 等待kthread_create_list上有新请求
set_current_state(TASK_INTERRUPTIBLE);

if (list_empty(&kthread_create_list)) {
// 没有待处理的创建请求,进入睡眠
schedule();
} else {
// 有创建请求,退出等待状态
__set_current_state(TASK_RUNNING);
}

// 处理所有待处理的kthread创建请求
spin_lock(&kthread_create_lock);
while (!list_empty(&kthread_create_list)) {
struct kthread_create_info *create;

// 从链表头部取出一个创建请求
create = list_entry(kthread_create_list.next,
struct kthread_create_info, list);
list_del_init(&create->list);
spin_unlock(&kthread_create_lock);

// 通过kernel_thread创建新的内核线程
create_kthread(create);

spin_lock(&kthread_create_lock);
}
spin_unlock(&kthread_create_lock);
}

return 0;
}

// 创建单个内核线程
static void create_kthread(struct kthread_create_info *create)
{
int pid;

// 实际上通过kernel_thread调用kthread函数
pid = kernel_thread(kthread, create,
CLONE_FS | CLONE_FILES |
CLONE_SIGHAND | CLONE_VM);

if (pid < 0) {
// 创建失败,通知等待者
create->result = ERR_PTR(pid);
complete(&create->done);
}
}

// 每个内核线程的入口包装函数
static int kthread(void *_create)
{
struct kthread_create_info *create = _create;
int (*threadfn)(void *data);
void *data;
struct kthread_self *self;
int ret;

// 初始化kthread的自引用结构
self = kmalloc(sizeof(*self), GFP_KERNEL);
self->threadfn = threadfn;
self->data = data;

// 通知kthreadd的调用者线程已创建完成
create->result = current;
complete(&create->done);

// 执行实际的线程函数
ret = threadfn(data);

// 线程退出
do_exit(ret);
}
```

kernel_init和kthreadd创建并启动后,CPU0进入idle循环。其他CPU(AP)的热插拔初始化由smp_init在kernel_init中触发:

```c
// init/main.c
static int __ref kernel_init(void *unused)
{
// 在启动1号进程之前,完成SMP初始化
// 唤醒所有AP(应用处理器)
smp_init();

// 完成CPU热插拔状态机
sched_init_smp();

// 唤醒所有AP后,执行剩余初始化
do_pre_smp_initcalls();

// 执行所有level 0的initcall
do_basic_setup();

// 最后,执行用户空间的init程序
if (ramdisk_execute_command)
run_init_process(ramdisk_execute_command);
// ...
}

// smp_init唤醒AP核心
void __init smp_init(void)
{
unsigned int cpu;

// 遍历所有可能的CPU
for_each_possible_cpu(cpu) {
if (cpu == smp_processor_id())
continue;

// 唤醒AP CPU
if (!cpu_online(cpu)) {
struct task_struct *idle;
idle = idle_thread_get(cpu);
// 发送IPI唤醒AP
cpu_up(cpu);
}
}
}
```

rest_init完成后,整个Linux内核的初始化序列结束。系统状态如下:CPU0运行在idle线程中,1号进程kernel_init正在加载用户空间init程序,2号进程kthreadd等待创建内核线程的请求,其他CPU(如果有)也在各自的idle循环中等待调度。内核至此完成了从引导到完整操作系统的全部初始化过程。

http://www.gsyq.cn/news/1564427.html

相关文章:

  • 基于拉格朗日对偶的大模型推理预算优化:动态平衡成本与质量
  • Mix-CALADIN:分布式计算破解混合整数规划难题
  • 2026年比较好的海口贸易公司注册/海口科技公司注册/海口公司注册年检品牌推荐 - 行业平台推荐
  • 提升住宅占用检测模型泛化能力:从数据工程到训练策略的实战指南
  • Ruby数组:高效、安全、语义化的数据处理核心
  • 2026年热门的geo排名/geo/geo推荐高端公司推荐 - 行业平台推荐
  • 5秒无损转换B站m4s视频:m4s-converter完整使用指南
  • 大语言模型在医疗诊断评估中的性能、校准与专家一致性研究
  • 2026年知名的湖南皮带输送机/湖南移动式皮带输送机生产厂家推荐 - 行业平台推荐
  • 用ASCII艺术增强大语言模型空间推理能力:从TEXT2SPACE数据集到工程实践
  • 如何高效无损合并B站缓存视频:m4s-converter完整使用指南
  • 3分钟掌握ncmdump:网易云音乐NCM格式转换终极教程
  • 3分钟掌握Translumo:告别外语障碍的实时屏幕翻译神器
  • 2026年可靠的工业切铝机/济南工业切铝机/济南高速切铝机主流厂家对比评测 - 品牌宣传支持者
  • AMD Ryzen调试神器:5步掌握SMU Debug Tool硬件级控制
  • 2026年比较好的唐山现做蜂蜜麻糖/低糖蜂蜜麻糖/唐山原味蜂蜜麻糖厂家精选合集 - 行业平台推荐
  • 嵌入式GUI开发实战:emWin配置优化与硬件加速集成指南
  • 2026年热门的唐山酥脆蜂蜜麻糖/低糖蜂蜜麻糖/老式蜂蜜麻糖生产厂家推荐 - 品牌宣传支持者
  • DS4Windows手柄固件更新终极指南:解决兼容性问题的完整方案
  • 科学智能体:从自动化工具到科研合作者的AI范式演进与实践
  • 大语言模型人格调控实战:MDS注入与混合方法详解
  • 2026年东莞TikTok培训骗局常见套路与防范指南 - 东莞选校指南
  • 机器学习在宇宙学参数推断中的应用:从归一化流到分布外检测
  • 2026年有实力的塑料电力管/安徽UPVC电力管/安徽拖拉电力管/拖拉电力管实力工厂推荐 - 品牌宣传支持者
  • 2026年比较好的板结料破碎机/湖南板结料破碎机优质公司推荐 - 品牌宣传支持者
  • OpenWRT插件管理终极指南:深度解析iStore架构设计与高级使用技巧
  • ControlFoley:跨模态冲突处理的可控视频到音频生成技术解析
  • Burp Suite Intruder四种攻击类型详解:Sniper、Battering Ram、Pitchfork与Cluster Bomb
  • LiveData核心原理深度解析:LifecycleBoundObserver与mVersion机制
  • LPC213x UART0驱动开发:从波特率计算、自动波特到中断FIFO的实战指南