Linux内核之进程上下文和中断上下文

来源:互联网 发布:淘宝页头尺寸 编辑:程序博客网 时间:2024/05/29 03:06

进程在执行的过程中始终会处于用户态和内核态中的一种,而内核态又分为运行于进程上下文(内核代表进程运行于内核空间)和运行于中断上下文(内核代表硬件运行于内核空间)。

进程上下文

所谓的进程上下文就是进程在执行的时候拥有的寄存器值、打开的文件、堆栈、内存信息等内容,其中也包括用户空间的进程通过系统调用传递给内核的参数还有保存的寄存器值和变量,参数。执行系统调用或者运行内核线程时内核处于进程上下文,此时内核使用的是内核栈。进程上下文可以睡眠,也可以调用调度程序。一个进程的上下文可以分为三个部分:用户级上下文、寄存器上下文以及系统级上下文

  • 用户级上下文: 正文、数据、用户堆栈以及共享存储区;
  • 寄存器上下文: 通用寄存器、程序寄存器(IP)、处理器状态寄存器(EFLAGS)、栈指针(ESP);
  • 系统级上下文: 进程控制块task_struct、内存管理信息(mm_struct、vm_area_struct、pgd、pte)、内核栈。
进程调度的上下文切换是切换上面所有的上下文,所以很耗时;而系统调用时发生的切换只是模式切换,主要时切换寄存器上下文,所以很快。
中断上下文
硬件通过触发信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理,中断上下文就可以理解为硬件传递过来的这些参数和内核需要保存的一些环境,主要是被中断的进程的环境。中断上下文与进程无关,不能通过current宏关联当前进程,所以中断上下文不可睡眠。此时中断处理程序使用的是中断栈。

内核处于中断上下文时不能干的事还挺多的,比如不能睡眠,不能主动让出CPU,所以也就不能尝试获取信号量,一般用的是自旋锁,在尽可能短的时间内完成,还有不能访问用户空间。

关于为什么中断上下文不能睡眠,在网上看到几个比较好的回答,贴出来
1

先把中断处理流程给出来

  1. 1.进入中断处理程序--->2.保存关键上下文---->3.开中断(sti指令)--->4.进入中断处理程序的 handler--->5.关中断(cli指令)---->6.写EOI寄存器(表示中断处理完成)---->7.开中断。

硬中断:
对应于上图的1、2、3步骤,在这几个步骤中,所有中断是被屏蔽的,如果在这个时候睡眠了,操作系统不会收到任何中断(包括时钟中断),系统就基本处于瘫痪状态(例如调度器依赖的时钟节拍没有等等……)

软中断:
对应上图的4(当然,准确的说应该是4步骤的后面一点,先把话说保险点,免得思一克又开始较真 )。这个时候不能睡眠的关键是因为上下文。
大家知道操作系统以进程调度为单位,进程的运行在进程的上下文中,以进程描述符作为管理的数据结构。进程可以睡眠的原因是操作系统可以切换不同进程的上下文,进行调度操作,这些操作都以进程描述符为支持。
中断运行在中断上下文,没有一个所谓的中断描述符来描述它,它不是操作系统调度的单位。一旦在中断上下文中睡眠,首先无法切换上下文(因为没有中断描述符,当前上下文的状态得不到保存),其次,没有人来唤醒它,因为它不是操作系统的调度单位。
此外,中断的发生是非常非常频繁的,在一个中断睡眠期间,其它中断发生并睡眠了,那很容易就造成中断栈溢出导致系统崩溃。

如 果上述条件满足了(也就是有中断描述符,并成为调度器的调度单位,栈也不溢出了,理论上是可以做到中断睡眠的),中断是可以睡眠的,但会引起很多问题.例 如,你在时钟中断中睡眠了,那操作系统的时钟就乱了,调度器也了失去依据;例如,你在一个IPI(处理器间中断)中,其它CPU都在死循环等你答复,你确 睡眠了,那其它处理器也不工作了;例如,你在一个DMA中断中睡眠了,上面的进程还在同步的等待I/O的完成,性能就大大降低了……还可以举出很多例子。 所以,中断是一种紧急事务,需要操作系统立即处理,不是不能做到睡眠,是它没有理由睡眠。

2

1、 中断处理的时候,不应该发生进程切换,因为在中断context中,唯一能打断当前中断handler的只有更高优先级的中断,它不会被进程打断,如果在 中断context中休眠,则没有办法唤醒它,因为所有的wake_up_xxx都是针对某个进程而言的,而在中断context中,没有进程的概念,没 有一个task_struct(这点对于softirq和tasklet一样),因此真的休眠了,比如调用了会导致block的例程,内核几乎肯定会死。

2、schedule()在切换进程时,保存当前的进程上下文(CPU寄存器的值、进程的状态以及堆栈中的内容),以便以后恢复此进程运行。中断发生后,内核会先保存当前被中断的进程上下文(在调用中断处理程序后恢复);

但在中断处理程序里,CPU寄存器的值肯定已经变化了吧(最重要的程序计数器PC、堆栈SP等),如果此时因为睡眠或阻塞操作调用了schedule(),则保存的进程上下文就不是当前的进程context了.所以不可以在中断处理程序中调用schedule()。



0 0
原创粉丝点击