欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

linux进程上下文、中断上下文介绍,以及为什么软中断不能睡眠?

最编程 2024-01-11 18:25:03
...

linux内核的软中断处理程序中能不能睡眠?

这是一个值得讨论的问题。

答案其实很简单,那就是不能。

因为Linux的软中断处理程序的运行上下文有可能是中断上下文。(注意此处是有可能,而并非一定)

那我们首先来了解下上下文,那什么是进程上下文?什么是中断上下文呢?

linux进程上下文、中断上下文介绍,以及为什么软中断不能睡眠?

1.先来看进程上下文

我们知道:用户空间的应用程序,通过系统调用,进入内核空间。

所谓的“进程上下文”,可以看作是用户进程传递给内核的这些参数以及内核要保存的那一整套的变量和寄存器值和当时的环境等。

2.再来看中断上下文

硬件通过触发信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的 一些变量和参数也要传递给内核,内核通过这些参数进行中断处理。

所谓的“ 中断上下文”,其实也可以看作就是硬件传递过来的这些参数和内核需要保存的一些其他环境。

接下来我们来看下软中断处理程序的调用时机。

linux进程上下文、中断上下文介绍,以及为什么软中断不能睡眠?

首先,大家知道,所有的软中断处理程序都要在do_softirq()中执行。

而do_softirq被调用的时机是:

  1. 从硬件中断处理程序返回时;
  2. 在ksoftirqd内核线程中;
  3. 在那些显式调用软中断的代码中,比如网络子系统中的NET_TX_SOFTIRQ和NET_RX_SOFTIRQ;

接着我们分析如上三种情形所处的上下文是什么?

linux进程上下文、中断上下文介绍,以及为什么软中断不能睡眠?

对于情形1, 我们知道硬件中断处理程序的最后会执行irq_exit(),但是请注意:irq_exit() 这个函数所在的上下文还是中断上下文!而irq_exit()会调用invoke_softirq(),而invoke_softirq又会调用do_softirq()函数执行软中断的操作。所以,此时,do_softirq()的执行环境还是中断上下文!但是与中断上半部不同的是,do_softirq()执行过程中是开中断的,能够被硬件中断所中断。

再看情形2,ksoftirqd是一个普通的内核线程,在ksoftirqd中会不断的检查和执行do_softirq()函数,所以,此时,do_softirq()的执行环境还是进程上下文!

再看情形3,在这种情形下,软中断会在处理程序中再次触发自己。在目前的内核实现中,如果这种触发发生在硬件中断处理程序中,那么并不会立刻处理,而是会留给ksoftirqd去处理。所以,在这种情形下,do_softirq()的执行环境还是进程上下文!

综合以上三种情形,如果一个函数既要适用进程上下文的运行环境,还要适用中断上下文的运行环境,那当然是以严格的那个环境为准了。所以,软中断的运行环境其实和中断的运行环境是一样的,都运行在中断上下文,既不能睡眠、也不能调用schedule让出cpu。

最后一个问题,软中断被硬件中断打断之后,如何再恢复列表执行呢?

linux进程上下文、中断上下文介绍,以及为什么软中断不能睡眠?

这个问题其实也很简单,分情况讨论:

  • 如果软中断的执行函数运行在进程上下文:在这种情况下被硬件中断打断,会把进程上下文信息记录在task_struct结构体中,等到合适的时机再调度执行;
  • 如果软中断的执行函数运行在中断上下文:那就涉及到中断的嵌套了。针对这种情形,其实也是有相应的机制保证的:

linux进程上下文、中断上下文介绍,以及为什么软中断不能睡眠?

__handle_domain_irq()负责内核的硬件中断的处理,在函数开始会保存中断上下文信息,在这个函数的结尾会恢复中断上下文信息。这样保证了硬件中断被优先级更高的中断抢占之后,原先的中断上下文信息可以得到保存,进而得到恢复和执行。