《LINUX内核总结(PPT课件)(修改版).ppt》由会员分享,可在线阅读,更多相关《LINUX内核总结(PPT课件)(修改版).ppt(90页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、Linux 简介l Linux是免费的、源代码开放的、符合POSIX标准规范的操作系统 。版本历史: 1991年,诞生 2001年,Linux2.4版内核发布 2003年,Linux2.6版内核发布l Linux特性 抢占式多任务处理 PMMU - 页式内存管理 VFS 虚拟文件系统 网络功能(如,支持TCP/IP ) 动态加载模块 支持SMP 支持绝大多数的32位和64位CPU 等一个典型的Linux操作系统的结构 (the users) Shells and commands Compilers and interpreters System libraries System-call i
2、nterface to the kernel Memory manager Signal 。 。 。 File systems Device drivers Process management Net work Kernel interface to the hardware Terminal controllers Terminals Device controllers Disks and tapes Memory controllers Physical memory 用户应用程序用户应用程序System call对硬件资对硬件资源的管理源的管理Shell,libKernelimple
3、mentation最简单也是最复杂的操作在控制台下输入在控制台下输入ls命令命令Shell程序分析输入参程序分析输入参数,确定这是数,确定这是ls命令命令调用系统调用调用系统调用fork生成生成一个一个shell本身的拷贝本身的拷贝什么是系统调用?为什么我们敲击键盘就会在终端上显示?fork是什么?为什么要调用fork?中断的概念,终端控制台设备驱动内核态用户态相关问题,内存保护进程的描述,进程的创建。COW技术系统调用是怎么实现的?软中断、异常的概念调用调用exec系统调用将系统调用将ls的可执行文件装入内存的可执行文件装入内存内存管理模块,进程的地址空间,分页机制,文件系统从系统调用返回从
4、系统调用返回如何做到正确的返回?堆栈的维护,寄存器的保存与恢复Shell和和ls都得以执行都得以执行进程的调度,运行队列等待队列的维护什么是shell?终端解释程序Linux 基本概念 系统调用 内存管理 进程管理 虚拟文件系统(VFS) 信号机制 内核初始化过程 提纲 用户态和内核态 系统调用意义 系统调用方法lCkcore的特权指令有:MFCR、MTCR、PSRSET、PSRCLR、RFI、RTE、STOP、WAIT、DOZEl这里所说的地址空间是虚拟地址而不是物理地址用户态和内核态(CPU:ckcore)内核态用户态标志PSR最高位1PSR最高位0运行指令无限制特权指令不可执行地址空间(
5、MMU)04G可访问02G可访问v区分用户态和内核态目的在于安全考虑:禁止用户程序和底层硬件直接打交道(最简单的例子,如果用户程序往硬件控制寄存器写入不恰当的值,可能导致硬件无法正常工作)禁止用户程序访问任意的物理内存(否则可能会破坏其他程序的正常执行,如果对内核所在的地址空间写入数据的话,会导致系统崩溃) 用户程序如何同设备打交道?例如,用户需通过网卡发送数据l 硬件被linux 内核隔离,只能通过内核实现。l 不可能直接调用操作系统的函数:不可行,也不安全。Linux提供的解决方法:系统调用系统调用的意义l 操作系统为用户态进程与硬件设备进行交互提供了一组接口系统调用 把用户从底层的硬件编
6、程中解放出来 极大的提高了系统的安全性 使用户程序具有可移植性l 基于ckcore的Linux kernel使用“trap 0”指令进行系统调用l 系统调用过程:执行陷阱异常指令trap 0 进入异常后,处理器PSR最高位被硬件置1,实现 普通用户 到 特权用户 的转变 根据系统调用号(r1传入),调用相应函数,满足用户需求系统调用返回,重新回到用户态,用户获得资源。l API和系统调用完全不同:API只是一个函数定义系统调用通过“软中断”向内核发出一个明确的请求trap 0l系统调用图解l Linux 2.6 提供了300多个系统调用,用户可以通过这些系统调用,及它们的组合实现对设备的操作。
7、l 通常,应用程序开发并不直接和系统调用打交道,而是用C库提供的一层包装函数。如,malloc() sbrk() sys_brk 内核函数 sys_brk 是45号系统调用, C库中它的系统调用方式可能是: movi r1, 45 trap 0 Linux 基本概念 系统调用 内存管理 进程管理 文件系统 信号机制 内核初始化过程 提纲 虚拟内存 虚拟内存到物理内存映射方法 物理内存和虚拟空间的管理 页面异常处理 页面交换策略 slab分配器 ioremap虚拟内存l 物理内存有限,是一种稀缺资源l 32位系统中,每个进程独立的占有4G虚拟空间。l 虚拟内存优势:用户程序开发方便保护内核不受恶
8、意或者无意的破坏隔离各个用户进程Ckcore的MMU虚拟地址空间l在保护模式下,即MMU开启时:USEG:用户程序可访问;需建立映射SSEG0:只有内核可访问;直接映射到0512M PA;可cacheSSEG1:只有内核可访问;也映射到0512M PA;不可cacheSSEG2:只有内核可访问;需建立映射在ckcore Linux中,2G以上是内核空间,2G以下是用户空间。虚拟地址到物理地址转换问题:内核为每个进程管理一个PT,占据内存 4MB。虚拟地址到物理地址转换:多级映射内核为每个进程管理一个PGD表, PT则需要时再分配。占内存 4kB+4KB*Nl 物理内存获取过程: 用户程序请求物
9、理内存 内核分配物理页面 内核填写对应页表项 用户程序获得物理内存l 从这个过程看出,内存管理的核心内容是:物理页面分配 和 所有进程页表的维护,即物理内存管理 和 虚拟空间管理。l物理内存管理l虚拟空间管理缺页异常处理l 物理页面并不预先分配,而是用到时发现缺少再分配。l 典型的页面分配过程: 用户程序访问虚拟空间 未建立映射,产生缺页异常 异常处理函数分配物理页面,并填好页表 异常返回,用户程序再次访问该虚拟空间Linux页面交换策略l 把暂时不用的页面存放到磁盘上,为其它急用的进程腾出空间,到需要时再从磁盘上读出来l 以时间换空间,因此: 有实时性要求的系统不宜使用 嵌入式只有Flash
10、闪存的系统不适合用slab分配器l由于操作系统在运行中会不断产生、使用、释放大量重复的对象, 所以对这样的重复对象的生成进行改进可以大大提高效率lSlab将缓存分为两种:1、专用高速缓存:用来存放内核使用的数据结构,例如:mm, skb, vm等等2、普通高速缓存:指存放一般的数据,比如内核为指针分配一段内存ioremap() :外部设备存储空间的地址映射l 通常的内存页面的管理,都是先分配虚存空间,再为此区间分配物理内存页面,并建立映射。l ioremap()则相反:要先有一个物理存储区间,如外设卡上的存储器出现在总线上的地址。再“反向”从该总线地址出发找到一片虚存区间,并建立映射。l 因为
11、只有内核才能对外部设备进行操作,所以相应的虚存区间是内核空间(2GB以上)。Linux 基本概念 系统调用 内存管理 进程管理 虚拟文件系统(VFS) 信号机制 内核初始化过程 提纲 进程描述符 进程的状态 进程调度 进程的切换 创建和撤销进程 0号线程和1号进程简单说进程的概念l进程是执行程序的一个实例l进程和程序的区别 几个进程可以并发的执行一个程序 一个进程可以顺序的执行几个程序标识一个进程l 使用进程描述符(task_struct)进程和进程描述符之间有非常严格的一一对应关系l 使用PID (Process ID,PID)每个进程有唯一的PID号,存放在进程描述符的pid域中进程描述符
12、l进程描述符提供了内核所需了解的进程信息 include/linux/sched.hstruct task_struct 数据结构很庞大 基本信息 管理信息 控制信息Linux2.6进程的状态TASK_RUNNING:可运行。TASK_INTERRUPTIBLE与TASK_UNINTERRUPTIBLE:睡眠等待。interrupt指软中断,即信号。前者可被信号唤醒,后者不能。TASK_STOPPED:暂停状态。主要用于调试。TASK_TRACED:进程被监控。TASK_DEAD:死亡状态。进程退出(调用do_exit())。TASK_WAKEKILL:在接收到致命信号时唤醒进程。l Linu
13、x2.6最新进程状态特性:1. TASK_DEAD状态区分两个不同的exit_state: EXIT_ZOMBIE:进程已终止,它正等待其父进程收集关于它的一些统计信息。 EXIT_DEAD:最终状态。其父进程已经通过 wait4() 或 waitpid() 调用收集所有统计信息,为了防止其他执行线程对同一进程也执行wait()类系统调用。2. 添加TASK_WAKEKILL 用于在接收到致命信号时唤醒进程:#define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)#define TASK_STOPPED (TASK_WAKEKIL
14、L | _TASK_STOPPED)#define TASK_TRACED (TASK_WAKEKILL | _TASK_TRACED)TASK_KILLABLE可以替代TASK_UNINTERRUPTIBLE在某些地方的应用。进程状态转换图TASK_DEAD( EXIT_ZOMBIE或或EXIT_DEAD)TASK_INTERRUPTIBLEorTASK_UNINTERRUPTIBLEorTASK_KILLABLE进程的内核堆栈l Linux为每个进程分配一个8KB大小的内存区域,用于存放该进程两个不同的数据结构:thread_info进程的内核堆栈 进程处于内核态时使用不同于用户态堆栈 内
15、核控制路径所用的堆栈很少,因此对栈和描述符来说,8KB足够了 thread_info 再看进程的概念l进程:有独立的内核堆栈(如8k),一个task_struct,专用的用户空间,并利用这些资源运行一个或者多个程序。 l 如果没有用户空间,则是 内核线程(thread); 如果共享用户空间,则称为 用户线程。l 进程和线程是进程调度的基本单位。进程的管理内核维护着若干进程链表,用于进程的管理和调度。l所有进程链表l进程可运行链表 内核把所有处于TASK_RUNNING状态的进程组织成一个可运行双向循环队列。调度函数通过扫描整个可运行队列,取得最值得执行的进程投入执行。避免扫描所有进程,提高调度
16、效率。问题:可运行进程(n)越多,每次调度的开销越大。这是2.4的O(n)调度算法的缺点。Linux 2.6 新引入O(1)调度算法运行时间和就绪队列中的进程数无关 调度时机用户进程自愿放弃CPU,如执行sleep()系统调用;系 统 调 用 中 , 需 要 等 待 时 , 直 接 调 用schedule()进行调度;系统调用、中断或异常处理完成后,返回到用户空间前,若当前进程的描述符中的need_resched = 1,则发生调度;内核是否为preemptible:视 C C中的中断处理完成,但返回内核空间时,是否仍有调度时机。进程切换(process switching)l 内核挂起正在C
17、PU上执行的进程,并恢复以前挂起的某个进程的执行,叫做进程切换,任务切换,上下文切换。进程上下文l包含了进程执行需要的所有信息 用户地址空间包括程序代码,数据,用户堆栈等 控制信息进程描述符,内核堆栈等 硬件上下文硬件上下文l 进程恢复执行前必须装入寄存器的一组数据,包括: 通用寄存器 系统寄存器l 所有的进程共享CPU的寄存器。因此,内核在恢复一个进程执行之前,必须确保每个寄存器装入了挂起进程时的值。这样才能正确的恢复一个进程的执行。l在linux中,一个进程的上下文主要保存在thread_info和thread_struct, 以及内核态堆栈中。l thread_infostruct th
18、read_info struct task_struct *task; /* main task structure */ unsigned long flags; struct exec_domain *exec_domain; /* execution domain */ int preempt_count; /* 0 = preemptable, BUG */ mm_segment_t addr_limit; struct restart_block restart_block; struct pt_regs *regs;l thread_structstruct thread_stru
19、ct unsigned long ksp; /* kernel stack pointer */ unsigned long usp; /* user stack pointer */ unsigned long sr; /* saved status register */ unsigned long crp2; /* cpu root pointer */ unsigned long esp0; /* points to SR of stack frame */ /* Other stuff associated with the thread. */ unsigned long addr
20、ess; /* Last user fault */ unsigned long baduaddr; unsigned long error_code; unsigned long trap_no;l pt_regsstruct pt_regs unsigned long pc; long r1; long syscallr2; unsigned long sr; long r2; long r3; long r4; long r5; long r6; long r7; long r8; long r9; long r10; long r11; long r12; long r13; long
21、 r14; long r15;l 进程切换的关键:内核堆栈的切换thread_info和内核态堆栈紧密联系在一起,切换内核态堆栈就意味着切换当前thread_info。l 进程执行需要的所有信息: 用户地址空间包括程序代码,数据,用户堆栈 控制信息进程描述符,内核堆栈等 硬件上下文current taskl用current宏获取当前task_struct:进程的创建l Linux提供了几个系统调用来创建:fork,vfork和clone系统调用创建新进程在内核中,它们都是调用do_fork实现的l fork:父进程的所有数据结构复制一份给子进程 clone:有选择的复制,其它通过指针共享 vf
22、ork:只复制task_struct和内核堆栈,所以子进程只是线程(没独立的用户空间)。execve系统调用l 通常,子进程从fork返回后会调用exec来开始执行新的程序,如:If (result = fork() = 0)/* 子进程代码 */if (execve(“new_program”,)0)perror(“execve failed”);exit(1);else if (resultsighand-actionsig-1 l进程信号相关结构关系:信号的发送l 信号可以发送给指定的一个或者多个进程。 l task_struct中有个pending域:struct sigpending
23、 pending;struct sigpendingstruct list_head list;sigset_t signal;其中,signal是标识未处理信号集的位图, list是sigqueue队列。l 信号发送具体体现:在指定进程task_struct的未处理信号集中添加该信号 。 l 可靠信号和不可靠信号:是否支持排队struct sigqueue struct list_head list; int flags; siginfo_t info; struct user_struct *user; 信号发送函数 int kill(pid_t pid,int signo) 将信号发送给
24、一个或一组进程。 对于pid的值 1. 0,发送信号给指定的进程; 2. = 0,把信号发送给同组的所有进程; 3. = -1,把信号发送给除0号、1号以及current之外的所有进程; 4. -1,把信号发送给指定的进程组中的所有的进程。 int sigqueue(pid_t pid, int sig, const union sigval val) 只能向一个进程发送信号,支持发送信号带附加信息。信号的响应l 响应时机:l 响应方式: 1. 显式的忽略信号 2. 执行系统默认的缺省操作,可以是:- Terminate:进程被杀死- Dump:进程被杀死,且如果可能,创建包含进程上下文的可用
25、于调试的core文件- Ignore:简单的忽略信号- Stop:进程被停止,状态置为TASK_STOPPED- Continue:如果进程被挂起,则状态置为TASK_RUNNING。否则忽略该信号3. 捕获信号- 为了执行用户希望的对某个事件的处理,可以由用户指定某个信号的处理函数。l do_signal() 一位一位的检查当前被挂起的非阻塞信号,调用sighand中action数组对应的处理方法: - 如果是SIG_IGN(忽略信号),忽略信号,返回; - 如果是SIG_DFL(缺省操作),找到对应的缺省处理方 式; - 如果信号有用户注册的处理程序,就调用handle_signal()强
26、迫执行该处理程序。l handle_signal() handle_signal运行在内核态,而信号处理程序在用户态的代码段中,运行在用户态。问题:1. 必须返回用户态执行信号处理程序;2. 必须按照原来进入内核的方式返回用户态;3. 一旦返回用户态,内核堆栈就被清空,如何保存内核堆栈的内容l Linux采用的解决办法:把保存在内核态堆栈中的上下文拷贝到当前进程的用户态堆栈中;建立好信号处理程序所需的堆栈环境;运行信号处理程序;结束时,调用sys_sigreturn()把上面保存的内核堆栈的内容再拷贝回内核堆栈;然后正常返回用户态。Linux 基本概念 系统调用 内存管理 进程管理 虚拟文件系
27、统(VFS) 信号机制 内核初始化过程系统初始化三个阶段l 第一阶段:CPU本身的初始化,例如虚拟地址模式的开启;l 第二阶段:系统基础设施的初始化,例如内存管理和进程管理的建立和初始化;l 第三阶段:根设备的安装和外部设备的初始化,载入init进程。第一阶段(head.S部分)l ckcore head.S 完成的主要工作:初始化PSR 使能cache 建立内核初始化需要的页面映射使能MMU 内核跳转到SSEG0段运行建立初始异常向量表初始化BSS段跳到start_kernel执行下一步初始化jsri第二阶段(start_kernel函数)l 初始化系统的核心数据结构,主要包括: setup
28、_arch():执行与体系结构相关的设置 trap_init():设置各种异常入口地址 init_IRQ():初始化IRQ中断处理机制 sched_init():初始化每个处理器的可运行进程队列,设置 系统初始化线程即0号线程。 softirq_init():对软中断子系统进行初始化 console_init():初始化控制台、显示器 init_modules():初始化kernel_module fork_init():定义系统最大进程数 最后进入rest_init()函数并调用kernel_thread()创建init内核线程,进行系统配置。 init内核线程占用进程描述表的第一项,由它来
29、创建其他进程完成系统初始化。第三阶段(init线程)l init内核线程首先调用do_basic_setup()来初始化外部设备及加载驱动程序。如: PCI总线初始化、网络初始化、文件系统初始化、加载文件系统。 l 初始化结束,打开/dev/console 设备重新定向控制台。l 用系统调用execve执行用户态程序/sbin/init。l 至此,linux的内核初始化工作完成。 Thank you!l参考资料lLinux内核源代码导读陈香兰 著.lLINUX内核源代码情景分析毛德操 胡希明 著.lc640 MMU Micro-Architecture中天 著.llinux2.6.30.4 内核源代码.