init 进程的创建

ps : 以下源码基于MTK3710

 图1、init

一、init 创建过程
Kernerl 启动分成两个过程:内核引导阶段、内核启动阶段。内核引导阶段对软硬件初始化结束后,会调用kernel/init 目录下main.c 文件中的start_kernel 函数开始进入内核启动阶段。在start_kernel 函数中会做一些初始化工作,例如初始化页地址、初始化软中断等,在此函数的最后会调用rest_init()来创建init 进程。下面依次查看相关源码:
1、start_kernel 函数源码:
asmlinkage __visible void __init start_kernel(void)
{
/*
* Set up the the initial canary ASAP: //进行一些初始化工作
*/
boot_init_stack_canary();
cgroup_init_early();
..............................
/* Do the rest non-__init'ed, we're now alive */
rest_init(); //调用此函数创建init 进程
}
2、rest_init 源码如下所示:
static noinline void __init_refok rest_init(void)
{
int pid;
rcu_scheduler_starting();
smpboot_thread_init();
/*创建两个内核线程
* We need to spawn init first so that it obtains pid 1, however
* the init task will end up wanting to create kthreads, which, if
* we schedule it before we create kthreadd, will OOPS.
*/
kernel_thread(kernel_init, NULL, CLONE_FS);
numa_default_policy();
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
rcu_read_lock();
kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
rcu_read_unlock();
complete(&kthreadd_done);
init_idle_bootup_task(current);
schedule_preempt_disabled(); //释放当前线程占用的cpu,激活其他线程
/* Call into cpu_idle with preempt disabled */ //减少系统资源占用
cpu_startup_entry(CPUHP_ONLINE);
}
说明:通过kernel_thread()启动内核线程,并通过kernel_init 函数创建init 进程的pid
号为1。Kthreadd 也是内核线程。通过命令“adb shell ps”也可以查看init 进程的id 号:
USER PID PPID VSIZE RSS WCHAN PC NAME
root 1 0 23976 1756 SyS_epoll_ 00000000 S /init
3、kernel_init 源码:
static int __ref kernel_init(void *unused)
{
int ret;
kernel_init_freeable();//调用此函数完成init 最终的创建
free_initmem();//释放内存
.........
#ifdef CONFIG_MTPROF
log_boot("Kernel_init_done"); //启动的log
#endif
if (ramdisk_execute_command) {
ret = run_init_process(ramdisk_execute_command);
if (!ret)
return 0;
}
//execute_command 是bootloader 传递给内核的参数,对此参数进行判空!
if (execute_command) {
//找到init 进程之后,调用run_init_process()
ret = run_init_process(execute_command);
if (!ret)
return 0;
}
//调用文件系统的init 进程,如果找不到就会寻找以下目录的init
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 进程进入用户空间
}
4、run_init_process()源码:
static int run_init_process(const char *init_filename)
{
argv_init[0] = init_filename;
return do_execve(getname_kernel(init_filename),
(const char __user *const __user *)argv_init,
(const char __user *const __user *)envp_init);
}
说明:do_execve()彻底解析内核调用用户空间代码入口函数
5、kernel_init_freeable()源码:
static noinline void __init kernel_init_freeable(void)
{
/*
* Wait until kthreadd is all set-up. 等待kthreadd 线程的创建
*/
wait_for_completion(&kthreadd_done);
/* Now the scheduler is fully set up and can do blocking allocations */
//现在调度程序已完全设置,可以执行阻塞分配。
gfp_allowed_mask = __GFP_BITS_MASK;
/*
* init can allocate pages on any node
*/
set_mems_allowed(node_states[N_MEMORY]);
/*
* init can run on any cpu.
*/
set_cpus_allowed_ptr(current, cpu_all_mask);
........................
//定义init 进程
if (!ramdisk_execute_command)
ramdisk_execute_command = "/init";
if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
ramdisk_execute_command = NULL;
prepare_namespace();
}
/*
* Ok, we have completed the initial bootup, and
* we're essentially up and running. Get rid of the
* initmem segments and start the user-mode stuff..
*/
/* rootfs is available now, try loading default modules */
load_default_modules();//加载一些默认的模块
}
从注释可以看出到这里已经完成了init 进程的创建。
二、内核调试方式
下面通过dump_stack()的内核debug 手段去抓取开机log,其中抓取
开机log 的方法:
1、在mtk 机器拨号界面上输入暗码:“*#*#84666364#*#*”,在
“Log and Debugging”中将MTKLogger 启动,然后执行关机开机操作。
它会将mtklog 文件放置在/sdcard/mtklog/目录中。
2 、将mtklog 通过adb 命令导到PC 上查看: adb pull
/sdcard/mtklog ./ (路径名)
在函数里面添加dump_stack():
printk(KERN_ALERT"-------------- dump_stack start----------------");
dump_stack();
printk(KERN_ALERT"--------------dump_stack end----------------");
重新编译烧录之后按照上述方法抓取开机log 的方法在kernel_log 中
打印出来的信息如下所示:


注:这是在上述的kernel_init 函数中去添加的dump_stack(),由于它是Kernel_thread 创建的pid=1 的进程,即子进程init。在linux中,一个新进程刚刚被创建,它第一次进入运行状态之前,为了让它”看起来像“是被切出而后被切入,就需要ret_from_fork 来制造现场。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值