嵌入式Linux内核体系架构李超lichao-runing@163.com13913004799嵌入式Linux内核总论PARTONE更新目标板上的系统嵌入式LinuxRedhatLinuxzImage2410.cramfs借助开发板上的Bootloader嵌入式Linux启动vivi(启动区)zImage(内核区)根文件系统区其它文件系统区知识回顾•Linux系统由内核和文件系统两大部分构成•内核各个模块之间相互联系,密不可分内核文件系统文件文件文件文件文件文件进程管理内存管理文件系统网络协议栈设备驱动管理底层硬件典型Linux系统构成图由CPU、内存、I/O、硬盘等底层硬件设备构成与计算机硬件进行交互,实现对硬件部件的编程控制和接口操作,调度对硬件资源的访问,并为计算机上的用户程序提供一个高级的执行环境和对硬件的虚拟接口。指那些向用户提供的服务被看作是操作系统部分功能的程序是指那些字处理程序、Internet浏览器程序或用户自行编制的各种应用程序1.Linux内核模式操作系统内核的结构模式主要可分为整体式的单内核模式和层次式的微内核模式在单内核模式的系统中,操作系统所提供服务的流程为:应用主程序使用指定的参数值执行系统调用指令(intx80),使CPU从用户态(UserMode)切换到核心态(KernelModel),然后操作系统根据具体的参数值调用特定的系统调用服务程序,而这些服务程序则根据需要再底层的一些支持函数以完成特定的功能。在完成了应用程序所要求的服务后,操作系统又从核心态切换回用户态,返回到应用程序中继续执行后面的指令2.Linux内核系统模块体系结构进程调度模块内存管理模块文件系统模块进程间通信模块网络接口模块负责控制进程对CPU资源的使用。所采取的调度策略是各进程能够公平合理地访问CPU,同时保证内核能及时地执行硬件操作用于确保所有进程能够安全地共享机器主内存区,同时,内存管理模块还支持虚拟内存管理方式,使得Linux支持进程使用比实际内存空间更多的内存容量。用于支持对外部设备的驱动和存储。虚拟文件系统模块通过向所有的外部存储设备提供一个通用的文件接口,隐藏了各种硬件设备的不同细节。从而提供并支持与其它操作系统兼容文件系统格式提供对多种网络通信标准的访问并支持许多网络硬件用于支持多种进程间的信息交换方式嵌入式内核知识点讲解大纲内存管理进程中断、异常和系统调用文件系统进程间通信设备驱动信号Linux2.6内核之进程组织李超讲课内容•进程基础–进程是什么?–怎样描述进程?•进程控制–进程的诞生–进程间的简单同步•进程间通信–进程间数据信息的传递PARTONE进程基础•关注点:–进程是什么–Linux怎样管理进程–在多任务系统中进程的调度1.1进程是什么?gedithello.c#includestdio.hvoidmain(){while(1){printf(“hello,Iamalive\n”);sleep(10);}}•任务:编写程序10秒钟向屏幕终端输出一句话:hello,Iamalive输出信息到屏幕开始睡眠10秒hello.c编译/汇编/连接可执行程序helloLinux操作系统代码段数据段堆栈段内存微处理器执行部件取指部件译码部件hello.c编译/汇编/连接可执行程序helloLinux操作系统代码段数据段堆栈段内存微处理器执行部件取指部件译码部件进程进程和可执行程序的关系进程是可执行程序的一次执行过程可执行程序进程静态动态剧本根据剧本的一次演出永远存放在磁盘中有诞生-执行-消亡的过程Linux操作系统社会进程是研究操作系统的核心人进程2进程1进程4进程3人人人居住场所房屋/内存社会关系有长辈/兄弟姐妹/子孙通讯方式手机,信件/管道、共享内存……人/进程1.2Linux中进程核心数据结构描述•在Linux系统中有多个进程同时存在,该如何描述这些进程呢?内存代码段数据段堆栈段进程1Linux内核区进程1“档案内存进程n进程n“档案进程控制块进程的“人事档案”structtask_struct{pid_tpid;pid_tpgrp;structtask_struct*p_opptr,*p_pptr,*p_cptr,*p_ysptr,*p_osptr;}定义在linux/sched.h当一个进程产生时,系统都会为它分配一个标识符,是唯一的。相当于人的身份证号码描述进程的社会关系进程的“人事档案”(CONT.)structtask_struct{……structmm_struct*mm;……}每个进程执行时都需要占用一定的内存区域,此区域用于保存该进程所运行的程序代码和使用的程序变量。每一个进程所占用的内存是相互独立的进程中使用的是虚拟内存空间具体的物理内存存放位置对于用户不可见所有进程的3-4GB空间被内核使用进程只会使用用户空间的一小部分且是离散的进程的“人事档案”(CONT.)structtask_struct{……structfs_struct*fs;structfiles_struct*files;……}fs描述了进程所处的文件系统相关信息files描述了一个进程打开文件的信息文件系统信息已打开的文件信息进程的“人事档案”(CONT.)structtask_struct{……volatilelongstate;……}一个进程在其运行期间的不同时刻,可能会处于不同的状态之下,它的状态可依据一定的条件和原因而变化进程的“人事档案”(CONT.)structtask_struct{……longcounter;longnice;unsignedlongpolicy;……}counter:CPU分配给进程的时间片nice:优先级权值policy:调度策略进程“人事档案”总结•进程的“人事档案”信息非常丰富,从各个侧面描述了进程•进程是Linux内核的核心,要了解Linux内核,必须首先掌握进程进程内存文件系统调度策略进程内存文件系统调度策略进程间通讯PARTTWO进程控制•关注点–创建进程–进程控制进程创建细胞细胞细胞细胞生殖进程创建如同细胞生殖Linux内核区进程创建•“身体”的复制•“档案”的“复制”内存代码段数据段堆栈段父进程父进程“档案进程控制块子进程子进程“档案“身体”复制“档案”复制fork():产生子进程头文件:#includeunistd.h格式:pid_tfork();返回值:0:子进程子进程ID(大于0的整数):父进程-1:出错调用fork()函数后,系统将创建一个与当前进程相同的新的进程。它与原有的进程具有相同的数据、连接关系和从同一处执行的连续性原有的进程称为父进程,新生的进程称为子进程例1产生新进程#includestdio.h#includesys/type.h#includeunistd.hvoidmain(){pid_tpid;printf(“Iamlonely,Iwillcreateababy\n”);pid=fork();if(pid0){printf(“createbabyfailed\n”);exit(1);}printf(“haha,familyaddanewmember\n”);}Linux内核区……voidmain(){……pid=fork();……}父进程“档案进程控制块子进程“档案“身体”复制“档案”复制内存代码段数据段堆栈段父进程fork()sys_fork(){…}子进程fork()?例1产生新进程#includestdio.h#includesys/type.h#includeunistd.hvoidmain(){pid_tpid;printf(“Iamlonely,Iwillcreateababy\n”);pid=fork();if(pid0){printf(“createbabyfailed\n”);exit(1);}printf(“haha,familyaddanewmember\n”);}Iamlonely,Iwillcreateababyhaha,familyaddanewmemberIamlonely,Iwillcreateababyhaha,familyaddanewmemberhaha,familyaddanewmemberVoidmain(){pid=fork();if(pid0){创建进程失败}elseif(pid==0){}else{}}可以使用返回值来让父子进程完成不同任务父进程单独完成的代码子进程代码都会执行父进程单独完成的代码#includestdio.h#includesys/type.h#includeunistd.hvoidmain(){pid_tpid;printf(“Iamlonely,Iwillcreateababy\n”);pid=fork();if(pid0){printf(“createbabyfailed\n”);exit(1);}elseif(pid==0)printf(“haha,Icometotheworld\n”);elseprintf(“haha,Ihaveababy\n”);printf(“wedoworktogether\n”);……}父进程输出结果子进程输出结果fork产生进程的缺陷•由于在使用fork时,内核会将父进程拷贝一份给子进程,但是这样的做法相当浪费时间,因为大多数的情形都是程序在调用fork后就立即调用exec,这样刚拷贝来的进程区域又立即被新的代码和数据覆盖掉Linux内核区……voidmain(){……pid=fork();……}父进程“档案进程控制块子进程“档案“身体”复制“档案”复制内存代码段数据段堆栈段父进程fork()sys_fork(){…}子进程fork()Linux内核区父进程“档案进程控制块“身体”复制“档案”复制内存代码段数据段堆栈段父进程fork()子进程fork()子进程“档案另外程序解决方案:采用vfork机制Linux内核区……voidmain(){……pid=vfork();……}父进程“档案进程控制块子进程“档案“档案”复制内存代码段数据段堆栈段父进程vfork()特点:父进程睡眠子进程运行代码空间只读不写·Linux内核区父进程“档案进程控制块子进程“档案“档案”复制内存代码段数据段堆栈段父进程vfork()另外程序身体复制产生异常Linux内核区父进程“档案进程控制块内存代码段数据段堆栈段父进程fork()另外程序子进程“档案vfork特点创建时,父子共享一块空间父进程睡眠,子进程运行父进程醒来时机:子进程运行结束子进程执行其它任务vfork使用头文件:#includeunistd.h#includesys/types.h格式:pid_tvfork();返回值:0:子进程子进程ID(大于0的整数):父进程-1:出错调用vfork()函数后,系统将创建一个与当前进程相同的新的进程。原有的进程称为父进程,新生的进程称为子进程#includestdio.h#includeunistd.h#includesys/types.hvoidmain(){pid_tpid;intx,y;x=20,y=30;pid=vfork();if(pid0){printf(oh,mygod,createababyfailed!\n);exit(1);}elseif(pid==0){x=40,y=50;sleep(1);printf(child:x=%d,y=%d\n,x,y);exit(0);}printf(parent:x=%d,y=%d\n,x,y);}运行结果:child:x=40,y=50parent:x=40,y=50exec()-执行其它程序•父进程创建子进程后,子进程一般要执行不同的程序。Linux提供了exec函数来实现这个目标•函数原型–inte