Linux内核中进程的初始化

分析start_kernel时应该会注意到Linux内核0号进程的初始化,见init/main.c。

set_task_stack_end_magic(&init_task); 其中,init_task为第一个进程(0号进程)的进程描述符结构体变量,它的初始化是通过硬编码方式固定下来的。除此之外,所有其他进程的初始化都是通过do_fork复制父进程的方式初始化的。

1号和2号进程的创建是start_kernel初始化到最后由rest_ init(如下图所示)通过kernel_thread创建了两个内核线程:一个是kernel_init,最终把用户态的进程init给启动起来,是所有用户进程的祖先;另一个是kthreadd内核线程,kthreadd内核线程是所有内核线程的祖先,负责管理所有内核线程。

在start_kernel()函数最后有arch_call_rest_init()函数,进入该函数我们就可以发现rest_init()函数了 

再进入rest_init()函数,我们可以看到通过kernel_thread创建了两个内核线程:

一个是kernel_init,最终把用户态的进程init给启动起来,是所有用户进程的祖先

另一个是kthreadd内核线程,kthreadd内核线程是所有内核线程的祖先,负责管理所有内核线程。

 

kernel_thread创建进程的过程和shell命令行下启动一个进程时fork创建进程的过程在本质上是一样的,都要通过复制父进程来创建一个子进程。

在系统启动时,除了前述0号进程的初始化过程是我们手工编码创建的之外,1号init进程的创建实际上是复制0号进程,根据1号进程的需要修改了进程pid等,然后再加载一个init可执行程序。同样地,2号kthreadd内核线程也是通过复制0号进程来创建的。通过如下kernel/fork.c中kernel_thread代码可以看到1号进程和2号进程最终都是通过_do_fork创建的,用户态通过系统调用fork创建一个进程最终也是通过_do_fork来完成的。

我们进入kernel_thread函数中去一探究竟,follow me!!!

 果然,在kernel_thread函数中发现了_do_fork(),我们再去_do_fork()里面去看看,走!

_do_fork具体进程的创建大概就是调用copy_process()把当前进程的描述符等相关进程资源复制一份,从而产生一个子进程,并根据子进程的需要对复制的进程描述符做一些修改,然后调用wake_up_new_task()把创建好的子进程放入运行队列(操作系统原理中的就绪队列)。在进程调度时,新创建的子进程处于就绪状态有机会被调度执行。


以上内容为中科大软件学院《Linux操作系统分析》课后总结,感谢孟宁老师的倾心教授,老师讲的太好啦(^_^)

参考资料:《庖丁解牛Linux内核分析》    孟宁  编著

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青衫客36

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值