至今为止, 我们所学到的大多数的知识, 包括语言, 数据结构, 动静态库等等的 都是在下面这3G, 也就是用户空间里的(进程等待, 信号之类的与内核有关的是在上面那1G里的)
所以对于我们来说, 我们并没有怎么接触上面的这些部分。
上面这部分(1G)映射的是操作系统的代码和数据
用户级页表和内核级页表
用户空间通过用户级页表
映射到自己的代码和数据, 而内核空间通过内核级页表
映射到操作系统的代码和数据
对于每一个进程 每个进程都需要有自己的用户级页表
, 而内核级页表只有1份
所以, 每一个进程的内核级空间对应的数据是一样的, 所以进程在切换的时候内核空间的内容其实是不变的
。
解释一下第三句话, 第三句话的意思就是 操作系统如果想执行自己的代码, 可以通过进程的PCB找到进程的地址空间然后执行对应的代码, 因为操作系统中一定有正在运行的进程。
操作系统的本质:
是一个基于时钟中断的一个死循环。
操作系统中有一个时钟芯片, 他会每隔很短很短的时间向计算机发送时钟中断
, 而一旦被CPU接受到, 就会根据中断向量表
去执行对应的方法, 这个方法就可能是操作系统中的某个方法。
举个例子:
我们CPU在调度进程的时候, 如果此时接收到了时钟中断, 就会将该进程剥离下来, 接着执行下一个进程。
用户态和内核态
CPU里面有一个CR3
寄存器, 它里面存放的是用户级页表的地址(物理地址)
CPU里面还有一个寄存器ecs
他的低两位表示CPU当前的工作模式
其中 00 表示内核态 11 表示用户态
所以我们来个总结
内核态: 允许你访问操作系统的代码和数据
用户态: 只能访问你自己的代码和数据
我们在调用系统调用的时候, 我们的操作系统会吧ecs的低2位设为00, 然后在仅此地址空间里的内核空间找到对应的代码然后执行就可以了。
信号的检测和处理的流程图
那么我们就有个问题, 如何我们的代码全是自己写的内容, 没有系统调用呢? 此时怎么进行信号的检测和处理呢?
由于我们的进程是在被不断的调度的, 当我们的进程被调度的时候, 操作系统会把进程的PCB 地址空间, 页表等等拿到CPU上, 此时肯定是内核态
的, 然后开始执行代码时 又是用户态的, 所以这之间一定存在 内核态向用户态的转变
, 也就一定会进行信号的检测和处理。
所以 不仅仅是系统调用会让进程从用户态
变成内核态
;