init进程的详解

以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。

参考博客

内核源码——C语言阶段的start_kernel函数_天糊土的博客-CSDN博客

分析根文件系统中的/linuxrc文件_天糊土的博客-CSDN博客

linux内核sys_mount()分析_kai_ding的博客-CSDN博客_sys_mount

【linux kernel】linux内核如何挂载根文件系统_iriczhao的博客-CSDN博客

一、前言提要

(1)start_kernel函数中的rest_init函数内容如下:

可知其调用kernel_thread函数启动了2个内核线程:kernel_init函数、kthreadd函数。

其中kernel_init函数内容如下,这个进程被称为init进程。

 

(2)注意,init进程和init程序(即linuxrc程序)是有区别的。

init进程一开始就有(是在rest_init函数中创建的),它运行于内核态,属于一个内核线程。后来init进程挂载根文件系统,并运行应用程序init程序后,init进程才从内核态进程转变为用户态进程。因为转变过程中进程号没有变,还是进程1,所以有人会把init程序(linuxrc程序)当做进程1。但其实init进程除了后面init程序的内容外,还包括内核态下挂载根文件系统等操作。

二、init进程从内核态向用户态的转变

1、一个进程先后两种状态

  • init进程刚开始运行的时候是内核态,它属于一个内核线程,然后运行一个用户态下面的程序后,把自己强行转成用户态(因为后面的进程需要工作在用户态下)。
  • init进程完成了从内核态到用户态的过渡,因此后续的其他进程都可以工作在用户态。

2、init进程在内核态下的工作内容

  • 主要是挂载根文件系统,并试图找到用户态下的那个init程序。(这句话看出,init进程是早于init程序运行的。)
  • init进程要把自己转成用户态就必须运行一个用户态的应用程序,要运行这个应用程序就必须得找到这个应用程序,要找到这个应用程序就必须得挂载根文件系统,因为所有的应用程序都在文件系统中。
  • 内核源代码中的所有函数都处于内核态,执行其中任何一个都不能脱离内核态。应用程序必须不属于内核源代码,这样才能保证应用程序处于用户态。这里执行的init程序和内核不在一起,由根文件系统另外提供。

3、init进程在用户态下的工作内容

  • init进程大部分有意义的工作都是在用户态下进行的。
  • init进程对操作系统的意义在于,其他所有的用户进程都直接或者间接派生自init进程

4、init进程如何从内核态跳跃到用户态

  • init进程处于内核态时,通过函数kernel_execve(见下文)来执行一个用户空间编译链接的应用程序就跳跃到用户态了。
  • 跳跃过程中进程号没有改变,一直是进程1。
  • 跳跃过程是单向的,一旦执行init程序转到用户态,整个操作系统就算真正运转起来了,以后只能在用户态下工作,用户态下想要进入内核态只能通过调用API。

三、init进程的工作内容

1、init进程打开了控制台

(1)linux系统中每个进程都有一个文件描述符表,表中存储的是本进程打开的文件。

(2)linux系统中一切皆是文件,因此设备也是以文件的方式来访问的。要访问一个设备,就要打开此设备对应的文件描述符。比如/dev/fb0这个设备文件就代表LCD显示器设备,/dev/buzzer代表蜂鸣器设备,/dev/console代表控制台设备。

(3)这里打开了/dev/console文件,并且复制了2次文件描述符,一共得到了3个文件描述符,分别是0、1、2,就是所谓的标准输入、标准输出、标准错误这3个文件描述符。

(4)进程1打开了这3个文件描述符,因此进程1衍生出来的所有的进程默认都具有这3个文件描述符。


2、init进程挂载了根文件系统

(1)prepare_namespace函数挂载根文件系统。

关于这个函数如何挂载根文件系统的,见博客linux内核如何挂载根文件系统 。

(2)uboot通过传参告知内核根文件系统的位置、根文件系统的文件系统类型等信息。 

  • 比如uboot传参中的“root=/dev/mmcblk0p2 rw”这一句就是告诉内核根文件系统在哪里。
  • 比如uboot传参中的“rootfstype=ext3”这一句就是告诉内核rootfs的类型。

(3)挂载结果(下面的描述是以inand启动为例,不是以tftp、NFS方式启动)

  • 如果内核挂载根文件系统成功,则会打印出:VFS: Mounted root (ext3 filesystem) on device 179:2。(也可能其他数字)
  • 如果挂载根文件系统失败,则会打印:No filesystem could mount root, tried:  yaffs2

(4)如果内核启动时挂载rootfs失败,则后面无法执行。

  • 内核中设置了启动失败后5s自动重启的机制,因此会看到反复重启的情况。

(5)如果挂载rootfs失败,可能的原因有

  • 最常见的错误就是uboot的bootargs设置不对。
  • rootfs烧录失败(fastboot烧录不容易出错)。
  • rootfs本身制作失败的。

3、init进程执行init程序(完成内核态到用户态的转变)

(1)执行prepare_namespace函数成功挂载rootfs后,接着执行init_post()函数。此函数进入rootfs中寻找应用程序的init程序,找到后调用run_init_process函数去执行。

(2)如何确定init程序是哪个文件?

  • 先判断uboot的传参cmdline中是否指定,如果指定则先执行cmdline中指定的程序。比如“init=/linuxrc”表示rootfs的根目录下的linuxrc程序就是init程序。下面代码就是执行/linuxrc的部分,其中变量execute_command的赋值过程见附录。它肯定是将cmdline解析后,从中得到 “init=/linuxrc” 这个项目。

  •  init=/linuxrc,这个/linuxrc一般是软连接,指向busybox,如下所示。

  • 如果uboot的传参cmdline中没有init=xx,或者cmdline中指定的这个xx执行失败,则执行备用方案:第一备用是/sbin/init,第二备用是/etc/init,第三备用是/bin/init,第四备用是/bin/sh。如果以上都不成功,则执行失败。

4、init进程构建了用户交互界面

(1)linux系统中一个进程的创建是通过其父进程创建出来的。根据这个理论只要有一个父进程就能生出一堆子孙进程了。

(2)init进程是其他用户进程的老祖宗。init启动了login进程(用户登录进程)、命令行进程(提供命令行环境)、shell进程(提供命令解释和执行)。

(3)shell进程启动了其他用户进程。命令行和shell一旦工作,用户就可以在命令行下通过./xx的方式来执行其他应用程序,每一个应用程序的运行就是一个进程。

四、附录

1、变量execute_command的赋值过程

在/init/main.c文件中有如下内容:

在/include/linux/init.h文件中,有如下定义:

/** Only for really core code.  See moduleparam.h for the normal way.** Force the alignment so the compiler doesn't space elements of the* obs_kernel_param "array" too far apart in .init.setup.*/
#define __setup_param(str, unique_id, fn, early)			\static const char __setup_str_##unique_id[] __initconst	\__aligned(1) = str; \static struct obs_kernel_param __setup_##unique_id	\__used __section(.init.setup)			\__attribute__((aligned((sizeof(long)))))	\= { __setup_str_##unique_id, fn, early }#define __setup(str, fn)	__setup_param(str, fn, fn, 0)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/461765.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

跟着石头哥哥学cocos2d-x(四)--cocos2dx中的动画以及TexturePacker使用

2019独角兽企业重金招聘Python工程师标准>>> 之前向Andreas Loew申请了一枚TexturePacker注册码,很快都下来了,作为回报我打算还是写一篇关于TexturePacker的使用博客吧,有兴趣的可以在这里申请密钥,http://www.codeandweb.com&am…

【C/C++学习】之七、指向函数的指针

什么是指向函数的指针 函数指针是指向函数的指针变量,不是指向对象的指针!函数指针本身应该是“指针变量”; “在C语言中,函数本身不是变量,但可以定义指向函数的指针,这种指针可以被赋值、存放于数组之中&…

头像和Karma汽车

Powered by Zoundry RavenTechnorati : Karma, 头像, 汽车 Del.icio.us : Karma, 头像, 汽车 转载于:https://www.cnblogs.com/bsmagic/archive/2008/08/06/1261858.html

内核中架构相关代码简介

以下内容源于朱友鹏《物联网大讲堂》课程的学习,如有侵权,请告知删除。 1、内核代码基本分为3块 (1)arch:本目录下全是cpu架构有关的代码 (2)drivers:本目录下全是硬件的驱动 &am…

All-In-One Code Framework [一站式示例代码库] 【转】

All-In-One Code Framework [一站式示例代码库]2010 对一站式示例代码库,对奋战在一站式示例代码库上的每一位工程师来说都是不同寻常的一年。 在我们共同努力和开发社区的支持下,该项目从一年前的草根雏形,成长为CodePlex排名前三&#xff0…

Repeater的嵌套

今天做了一个小项目学习一下&#xff0c;是关于两个Repeater的嵌套使用的&#xff1a; 关于Repeater的嵌套&#xff0c;关键在于数据项的绑定。 首先&#xff0c;外Repeater需要设置OnItemDataBound事件&#xff0c;在事件中添加子Repeater的数据项绑定&#xff1b; <asp:Re…

Ioc容器Autofac介绍

Autofac是轻量级的开源Ioc容器&#xff0c;在这里可以下载http://code.google.com/p/autofac/。如果你用过其他的Ioc容器&#xff0c;那么学习Autofac使用也会比较容易&#xff0c;下面将通过一些例子来讲解其用法。 先看一个例子&#xff1a; 首先新建一个工程&#xff0c;添加…

汇编指令的学习2——常用的ARM指令

一、常用ARM指令1&#xff1a;数据处理指令 &#xff08;1&#xff09;数据传输指令 mov mvn&#xff08;源目标按位取反后赋给目标&#xff09; &#xff08;2&#xff09;算术指令 add sub rsb adc sbc rsc &#xff08;3&#xff09;逻辑指令 and orr eor …

cocos2dx 3.4 截图代码

Size size Director::sharedDirector()->getWinSize(); //定义一个屏幕大小的渲染纹理 RenderTexture* pScreen RenderTexture::create(size.width,size.height, kCCTexture2DPixelFormat_RGBA8888); log("-------log1---");//获得当前的场景指针 Scene* pC…

NSURLRequest详解IOS最基础的api

http://blog.csdn.net/bl1988530/article/details/6590099转载于:https://www.cnblogs.com/qiqibo/archive/2012/08/22/2650996.html

正则表达式 Mather类的使用

Matcher类: 使用Matcher类,最重要的一个概念必须清楚:组(Group),在正则表达式中 ()定义了一个组,由于一个正则表达式可以包含很多的组,所以下面先说说怎么划分组的, 以及这些组和组的下标怎么对应的. 下面我们看看一个小例子,来说明这个问题 \w(\d\d)(\w) 这个正则表达式有三…

ARM协处理器的汇编指令

以下内容源于网络资源的学习与整理&#xff0c;如有侵权请告知删除。 一、协处理器的简介 协处理器&#xff08;cp&#xff0c;coprocessor&#xff09;是SoC内部的处理单元&#xff0c;用来协助主CPU实现一些特定的功能&#xff0c;比如MMU、cache、TLB等内容。ARM在设计上支…

用代码实现Sharepoint2010的个人信息的照片上传(2)(原创)

用代码从AD读取照片信息并同步到SharePoint2010的个人照片信息中 前言 上篇我们讲到用代码实现了照片信息同步到SharePoint2010的个人照片信息中&#xff0c;但是做的是从文件夹读取照片信息到SharePoint2010,今天我们要做的从AD的thumbnailPhoto属性中读取照片信息到SharePoin…

HTML5实现Word中文字全环绕图片效果

实现这个功能是当时看见数字报的展示出来的编排方式&#xff0c;就是图片热点&#xff0c;而且下载打开还是PDF的&#xff0c;让我这个WP用户咋个看。想实现Word中的编排方式&#xff0c;也需要浏览器支持Word插件&#xff0c;火狐、谷歌、Opera这些都要另外弄插件&#xff0c;…

汇编指令的学习4——ldm/stm指令、栈的处理

1、为什么需要多寄存器访问指令&#xff1f; ldr/str每周期只能访问4字节内存&#xff0c;如果需要批量读取、写入内存时太慢&#xff0c;解决方案是stm/ldm ldm (load register mutiple) stm&#xff08;store register mutiple&#xff09; 2、举例&#xff1a;stmia sp,…

第一课 GCC入门

1序言 gcc是一个可移植的编译器&#xff0c;支持多种硬件平台&#xff1b;也不仅仅是一个本地编译器也是一个跨平台编译器&#xff1b;支持多张语言编译时按照模块化设计支持多种语言。 gcc编译过程&#xff1a;预处理&#xff08;预处理器&#xff09;&#xff1b;编译&#x…

[转载] 晓说——第9期:多如牛毛严酷无比的美国那些法

转载于:https://www.cnblogs.com/6DAN_HUST/archive/2012/08/26/2657224.html

ARM的汇编伪指令【伪指令的解释】

本文作为此博文的伪指令章节的补充说明。 伪指令的含义 伪指令本质上不是指令。伪指令由编译器环境提供&#xff0c;用来指导编译过程&#xff0c;经过编译后伪指令不会生成机器码。 伪指令是和具体的编译器相关的。我们使用GNU工具链&#xff0c;因此学习GNU环境下的汇编伪指令…

关注 Imagine Cup 2010, 参与软件设计“最具人气奖”投票

关注 Imagine Cup 2010, 参与软件设计“最具人气奖”投票 Imagine Cup 2010全球总决赛将于7月3日到7月8日在波兰华沙举行。现在通过参与软件设计“最具人气”奖投票&#xff0c;你也可以参与到Imagine Cup 2010中。了解全球学生是如何用科技创新帮助我们解决人类面临的最困难问…

浏览器模拟用户登陆

javascript:document.getElementById(user).valuejack;document.getElementById(password).valuetest;submitForm();void(0);转载于:https://www.cnblogs.com/ahghy/p/3488839.html