Init进程

本文详细解读了Linux从启动到用户登录的过程,包括init进程的作用、Upstart的使用、init/main.c中的start_kernel函数及其关键代码分析,以及进程切换机制等核心内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


李峰

原创作品转载请注明出处

《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

linux启动流程

从计算机上电开始到内核加载:

计算机如何启动
计算机如何启动 1

从内核加载到用户登录如下图,

init(为英语:initialization的简写)是 Unix 和 类Unix 系统中用来产生其它所有进程的程序。它以守护进程的方式存在,其进程号为1。
——— [维基百科]
Upstart是一个基于事件的初始化守护进程,用于替代传统的init(多种类Unix计算机操作系统启动时用于执行任务的程序)。——— [维基百科]

Linux启动流程
Linux启动流程 2

init进程是什么

init进程是一个普通的用户态进程,特别之处在于它是所有进程的祖宗。它是内核初始化和用户态初始化的结合点,在内核初始化的结尾部分,init进程被启动,然后开始用户态的初始化。

init进程受什么控制

init进程运行完全受/etc/inittab的控制,如果你要追踪内核的初始化,则从init/main.c文件中的start_kernel()函数开始,如果你要追踪用户态的初始化,则要从/etc/rc.d/rc.sysinit脚本开始。

init进程怎么启动的

init进程是内核启动的第一个用户态进程,而start_kernel()是内核汇编和c语言的连接点,在该函数之前,汇编代码会完成一些初始化,比如为c语言准备运行环境,此函数就像c程序的main函数一样。
init/main.c中,start_kernel()是内核的入口,在该函数的最后一行,执行了rest_init();,这个函数里通过函数kernel_thread(kernel_init, NULL, CLONE_FS);创建了一个内核线程,该线程会运行static int __ref kernel_init(void *unused)函数,在该函数的结尾处,有如下代码:

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 process,首先运行/sbin/init,如果失败则运行/etc/init,如果又失败则运行/bin/init,然后是/bin/sh,该函数运行完成以后,init process就被创建,预示着内核初始化结束,用户态初始化开始。

start_kernel函数
start_kernel函数 3

kernel_thread如何创建内核线程的呢?

kernel_thread函数如下:

pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
    return do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn,
        (unsigned long)arg, NULL, NULL);
}

第一个参数即kernel_init函数的地址,为此进程执行时需要执行的函数,此函数返回值为int型,参数是一个void 指针,穿进去的第二个参数是此函数的参数,这里实际值设置为NULL, 第三个参数是创建新进程的标志位,在内核中有定义,这里实际取CLONE_FS ,宏定义如下:#define CLONE_FS 0x00000200 /* set if fs info shared between processes */。此函数返回pid_t变量,即新创建的进程的进程号。
函数内部调用了do_fork函数,函数分析见:do_fork分析,下面分析此函数的关键代码:

p = copy_process(clone_flags, stack_start, stack_size,
             child_tidptr, NULL, trace);

copy_process函数创建一个和原来进程一摸一样的进程,复制了原来进程用到的寄存器,和相应的进程环境。然后返回struct task_struct指针,即进程描述符,函数分析见窥探 kernel — copy_process

kernel_thread()
kernel_thread()函数

进程的切换机制

进程切换统一发生在schedule(void)函数中,核心函数是__schedule(void),函数分析见 schedule()函数篇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值