用户态和内核态
用户态与内核态
当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态(或简称为内核态)。
此时处理器处于特权级最高的(0 级)内核代码中执行。当进程处于内核态时,执行的内核代码会使用当前进程的内核栈。每个进程都有自己的内核栈。
当进程在执行用户自己的代码时,则称其处于用户运行态(用户态)。
即此时处理器在特权级最低的(3 级)用户代码中运行。当正在执行用户程序而突然被中断程序中断时,
此时用户程序也可以象征性地称为处于进程的内核态。因为中断处理程序将使用当前进程的内核栈。这与处于内核态的进程的状态有些类似。
换言之,发生系统调用时进入核心态。
从图上可以看出来通过系统调用将Linux整个体系分为用户态和内核态(或者说内核空间和用户空间)。
linux的内核(kernal),它是一种特殊的软件程序,它控制计算机的硬件资源,
例如协调CPU资源,分配内存资源,并且提供稳定的环境供应用程序运行。
用户态就是提供应用程序运行的空间,为了使应用程序访问到内核管理的资源例如CPU,内存,I/O。
内核必须提供一组通用的访问接口,这些接口就叫系统调用。
-
系统调用
当你的代码需要做IO操作(open、read、write)、或者是进行内存操作(mmpa、sbrk)、甚至是说要获取一个系统时间(gettimeofday),
就需要通过系统调用来和内核进行交互。无论你的用户程序是用什么语言实现的,是php、c、java还是go,只要你是建立在Linux内核之上的,
你就绕不开系统调用。注意:不同的Linux发行版本提供的系统调用数量也不尽相同,大致在240-350之间。
这些系统调用组成了用户态跟内核态交互的基本接口。 -
库函数
库函数就是屏蔽这些复杂的底层实现细节,减轻程序员的负担,从而更加关注上层的逻辑实现。
它对系统调用进行封装,提供简单的基本接口给用户,这样增强了程序的灵活性,
当然对于简单的接口,也可以直接使用系统调用访问资源,例如:open(),write(),read()等等。
库函数根据不同的标准也有不同的版本,例如:glibc库,posix库等。 -
shell
shell顾名思义,就是外壳的意思。就好像把内核包裹起来的外壳。它是一种特殊的应用程序,俗称命令行。
为了方便用户和系统交互,一般一个shell对应一个终端,呈现给用户交互窗口。当然shell也是编程的,
它有标准的shell语法,符合其语法的文本叫shell脚本。很多人都会用shell脚本实现一些常用的功能,可以提高工作效率。
从用户态到内核态切换可以通过三种方式:
- 系统调用,这个上面已经讲解过了,在我公众号之前的文章也有讲解过。其实系统调用本身就是中断,但是软件中断,跟硬中断不同。
- 异常:如果当前进程运行在用户态,如果这个时候发生了异常事件,就会触发切换。例如:缺页异常。
- 外设中断:当外设完成用户的请求时,会向CPU发送中断信号。