当前位置: 首页 > 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.jsqmd.com/news/1052507/

相关文章:

  • 后端开发新趋势:探索前沿技术栈的融合应用
  • CLion优化器:提升深度学习模型泛化能力的谨慎优化策略
  • mTLS客户端认证的可用性挑战:从工具设计到用户认知的全面分析
  • 提升住宅占用检测模型泛化能力:从数据工程到训练策略的实战指南
  • 基于分层智能体架构的AI模型自动化构建系统设计与实践
  • 2026年靠谱的杀菌机饮料设备/梁山杀菌机饮料设备/包装机饮料设备深度厂家推荐 - 品牌宣传支持者
  • Ruby数组:高效、安全、语义化的数据处理核心
  • ProVoice-Bench:语音智能体主动式评估框架的设计与实践
  • 2026新乡漏水检测维修本地口碑防水商家榜单:厨卫/阳台/屋面/地下室渗漏水维修,持证施工+明码实价,防水补漏公司TOP5推荐 - 即刻修防水
  • 2026年靠谱的做网站/定制网站/网站建设全国知名公司 - 行业平台推荐
  • 2026年比较好的济南高速切铝机/济南全自动切铝机/济南切铝机优质厂家推荐榜 - 行业平台推荐
  • 2026年热门的geo排名/geo/geo推荐高端公司推荐 - 行业平台推荐
  • emWin GUI控件实战:SCROLLBAR、SLIDER与SPINBOX的深度解析与应用
  • 2026年靠谱的泡沫包装/泡沫包装制品/成都泡沫制品源头工厂推荐 - 行业平台推荐
  • 多级蒙特卡洛梯度估计:原理、复杂度分析与优化策略
  • 基于LLM的用户体验评分预测:从非结构化评论到结构化数据资产
  • 2026揭阳漏水检测维修本地口碑防水商家榜单:厨卫/阳台/屋面/地下室渗漏水维修,持证施工+明码实价,防水补漏公司TOP5推荐 - 即刻修防水
  • 5秒无损转换B站m4s视频:m4s-converter完整使用指南
  • TMSpeech终极指南:Windows实时语音转字幕完整解决方案
  • 2026年比较好的无锡公司推广/外贸geo推广哪家正规 - 行业平台推荐
  • UniDoc-RL:基于强化学习的视觉文档理解框架设计与实践
  • 2026年热门的GEO营销/GEO搜索/GEO排名/GEO推广优选服务公司 - 行业平台推荐
  • 微信小程序二维码生成终极指南:weapp-qrcode完整解决方案
  • 大语言模型在医疗诊断评估中的性能、校准与专家一致性研究
  • 张量网络在机器学习中的应用:从模型压缩到可解释性分析
  • 2026年有实力的外贸网站建设/网站搭建/做网站/网站优化公司推荐 - 品牌宣传支持者
  • 3分钟掌握ncmdump:网易云音乐NCM格式转换终极教程
  • 2026文山漏水检测维修本地口碑防水商家榜单:厨卫/阳台/屋面/地下室渗漏水维修,持证施工+明码实价,防水补漏公司TOP5推荐 - 即刻修防水
  • 2026年知名的湖南皮带输送机/湖南移动式皮带输送机生产厂家推荐 - 行业平台推荐
  • 如何高效无损合并B站缓存视频:m4s-converter完整使用指南