标签:原因 级别 掌握 drive 信号 关系 创建 运行环境 bottom
1. 内存管理模型
(1)子系统简介
System Call Interface(SCI)系统调用接口 |
|
Process Management(PM) |
Virtual File System(VFS)虚拟文件系统 |
Memory Management(MM) |
Network Stack |
Arch 体系结构相关 |
Device Drivers(DD) |
这七个子系统之间都是有所联系的,我们这阶段学习的是驱动子系统。它和内存管理子系统、进程管理子系统、VFS子系统之间都是联系密切的。我们这一个专题要研究的就是内存和进程这两个子系统。
内存和CPU是运行系统中十分中要的组成部分,对于内存来说,它虽然是有效的,但是它也是有限的。
(2)管理模型
上面的是一幅经典的内存分配的图,我们用线框起来部分的作用是物理内存的分配,其他部分的功能是地址映射。
从而我们也能明白内存管理子系统的职能是:
2. 地址映射管理
地址映射管理主要体现在:虚拟地址空间分布和虚拟地址转化为物理地址的方法上。
(1)虚拟地址空间分布
我们前面学习的裸机开发,从芯片手册上看到的GPIO地址等等,这些都是物理地址。我们最后要访问到硬件,那么一定是要访问物理地址的。但是在linux系统当中,我们都不用物理地址,我们用的是虚拟地址,也就是程序当中出现的地址。例如我们用啊malloc函数分配出来的内存,就是虚拟地址。
我们linux系统支持的虚拟地址空间是由它的硬件来决定的。例如,我们32的处理器,地址总线是32位,它能访问的虚拟地址空间是232也就是4G。
这4G的空间又被分成了两个部分,0G-3G部分是用户空间,放的是用户程序也就是应用程序。3G-4G使我们的内核空间,其中被分为了4个部分。
我们之所以做这样的划分,是因为它们到物理内存的映射关系是不同的。所由的关系在上面的图上都能看出来。
(2)虚拟地址如何转化为物理地址
我们将管理模型图进行简化,如下:
我们的cr3寄存器作为基地址,我们将32位的虚拟地址的高10位取出来作为一个偏移,这样就能从我们的页目录里面找到一个地址。页目录里面存放的是页表的基地址,加上我们32位虚拟地址的中间地址,能在页表里面找到一个地址。这个地址是指向我们物理页的基地址,加上32位虚拟地址的前12位就能找到我们物理页(也叫页帧,一个页帧一般4Kb)。
3. 物理地址分配管理
我们现在思考一个问题,究竟什么时候分配物理内存?有人说是运行new和malloc函数的时候。这在其他的系统中可能对,但是在linux系统中不对。linux实行的是虚拟地址管理的机制。
当我们用函数申请了虚拟地址,它不会直接就给分配对应的物理地址,为了减少浪费,只有我们访问虚拟地址的时候,虚拟地址才会被分配物理地址。
我们在上图中可以看到,只有Kmalloc函数是直接申请物理内存区域的。其他的函数都是在页面异常(也就是访问)的时候才会申请物理内存的。
大纲
Linux进程要素:程序与进程、进程4要素、Linux进程状态、进程描述结构
Linux进程调度:调度策略、调度时机、调度步骤
一.Linux进程管理子系统
1. 进程与程序
程序:
存放在磁盘上的一系列代码和数据的可执行映像,是一个静止的实体。
进程:
是一个执行中的程序,它是动态的实体。
2. 进程的四要素(必背)
3. Linux进程状态
三态图:
linux细分的三态图:
进程正在被CPU执行,或者已经准备就绪,随时可以执行。当一个进程刚被创建时,就处于TASK_RUNNING状态。
处于等待中的进程,待等待条件为真时被唤醒,也可以被信号或者中断唤醒。
处于等待中的进程,待资源有效时唤醒,但不可以由其它进程通过信号(signal)或中断唤醒。
Linux2.6.25新引入的进程睡眠状态,原理类似于TASK_UNINTERRUPTIBLE,但是可以被
致命信号(SIGKILL)唤醒。
正处于被调试状态的进程。
进程退出时(调用do_exit),所处的状态。
4. Linux进程描述
在Linux内核代码中,线程、进程都使用结构task_struct(sched.h)来表示,它包含了大量描述进程/线程的信息,其中比较重要的有:
v pid_t pid; //进程号
v vlong state; //进程状态
v vint prio; //进程优先级
v
二.进程调度
1. 什么是调度
从就绪的进程中选出最适合的一个来执行。学习调度需要掌握哪些知识点?
2. 调度策略
SCHED_NORMAL(SCHED_OTHER):普通的分时进程。
vSCHED_FIFO :先入先出的实时进程。
SCHED_RR:时间片轮转的实时进程(一个进行运行了一个片轮,下个进程运行)。
SCHED_BATCH:批处理进程。
SCHED_IDLE: 只在系统空闲时才能够被调度执行的进程。
实时进程的优先级别比普通的进程的优先级别高,调度的时候,优先调用。
3. 调度机制
什么时候发生调度?即schedule()函数什么时候被调用?
(1)主动式:
在内核中直接调用schedule()。当进程需要等待资源等而暂时停止运行时,会把自己的状态置于挂起(睡眠),并主动请求调度,让出CPU。
范例:
current->state = TASK_INTERRUPTIBLE; (current是个宏,是task_struct类型的指针,state记录的是一个状态,TASK_INTERRUPTIBLE表示阻塞态)
schedule();
(2)被动式:
被动式调度又名:抢占式调度。分为:用户态抢占(Linux2.4、Linux2.6)和内核态抢占 (Linux2.6)。
用户态抢占:
用户抢占发生在:
内核即将返回用户空间的时候,如果need_resched标志被设置,会导致schedule()被调用,即发生用户抢占。
内核态抢占:
用户态抢占缺陷
进程/线程一旦运行到内核态,就可以一直执行,直到它主动放弃或时间片耗尽为止。这样会导致一些非常紧急的进程或线程将长时间得不到运行,降低整个系统的实时性。
改进方式
允许系统在内核态也支持抢占,更高优先级的进程/线程可以抢占正在内核态运行的低优先级进程/线程。
内核抢占可能发生在:
注意,在支持内核抢占的系统中,某些特例下是不允许抢占的:
v 内核正在运行中断处理。
v 内核正在进行中断上下文的Bottom Half(中断的底半部)处理。硬件中断返回前会执行软中断,此时仍然处于中断上下文中。
v 进程正持有spinlock自旋锁、writelock/readlock读写锁等,当持有这些锁时,不应该被抢占,否则由于抢占将可能导致其他进程长期得不到锁,而让系统处于死锁状态。
v 内核正在执行调度程序Scheduler。抢占的原因就是为了进行新的调度,没有理由将调度程序抢占掉再运行调度程序
(3)抢占计数:
为保证Linux内核在以上情况下不会被抢占,抢占式内核使用了一个变量preempt_count,称为内核抢占计数。这一变量被设置在进程的thread_info结构中。每当内核要进入以上几种状态时,变量preempt_count就加1,指示内核不允许抢占。每当内核从以上几种状态退出时,变量preempt_count就减1,同时进行可抢占的判断与调度。
调度步骤--Schedule函数工作流程如下:
v 清理当前运行中的进程;
v 选择下一个要运行的进程;
v 设置新进程的运行环境;
v 进程上下文切换。
标签:原因 级别 掌握 drive 信号 关系 创建 运行环境 bottom
原文地址:https://www.cnblogs.com/free-1122/p/10902183.html