FreeRTOS-为什么关中断之后切换进程?

https://mp.weixin.qq.com/s/S5HBH3RTo0B2irr8sGwDdw

一. 基本问题

FreeRTOS会在关键区即taskENTER_CRITICAL()和taskEXIT_CRITICAL()包裹的区间中,执行进程切换。即在关闭中断的时候,进行进程切换。

我们已经知道,即便关闭中断,PowerPC的sc中断,还是可以得到响应。但是时钟中断呢?这是个外部中断,无法得到响应。

那么是何时打开的中断呢?新进程切入之后,立即打开中断?在多个TASK级别做开关中断配对?

1.关键区和关键资源

或者叫竞争区间,使用PV原语保护,操作系统基本概念。在FreeRTOS中,为使用taskENTER_CRITICAL()和taskEXIT_CRITICAL()包裹的区间。

关键区中使用即PV原语保护的资源为关键资源。

2.基本同步机制:开关中断

单核CPU存在两个并行流程:TASK和中断ISR。中断可以打断TASK的执行。所以TASK中的关键区间需要使用开关中断保护,而中断ISR就不需要再关中断了。这是最基本的同步机制。

如果中断存在优先级,高优先级中断可以打断低优先级中断,则存在三个并行流程:TASK、低优先级中断ISR和高优先级中断ISR。如此仅仅关闭中断,已经无法起到保护关键区的作用。需要把CPU的当前中断响应级别提升到关键区间所需要的最高级别。这里的所需要,是指会使用到被保护资源的最高优先级的中断的优先级。即便不是最高,但其上优先级的中断ISR不使用被保护资源,则不会导致死锁。

多核CPU除了考虑本核的同步外,还需要考虑与其他核的同步,需要使用系统级别的标志。因为多个核共享同一个内存空间,所以这个同步标志,可以是一个存在内存中的变量。

3.关键区尽量短

关闭中断,会使CPU无法及时响应外部中断。所以为了提高响应的实时性,需要使关键区间尽量短。也就是关闭中断的时间尽量短。不涉及关键资源的操作,尽量放在关键区间之外执行。

4.PV操作成对出现,降低复杂度

为了降低程序的复杂度。使同步操作更易阅读理解,同时降低出错的概率。PV操作一般成对出现,并且出现在同一个函数中。为了保证成对出现,甚至可以使用goto语句。即使用if判断到需要直接退出的例外情况时,不是直接在if中开中断然后退出,而是使用goto跳转到成对的唯一一个开中断操作。

5.关键区间中切换进程提升了复杂度

所以关键区间中,在关闭中断的状态下切换进程,提升了代码的复杂度。如何保证开关中断的动作成对出现,变成了一个很复杂的问题。

下面我们跟踪xSemaphoreGive/xSemaphoreTake的流程,来看何时打开的中断。

二.Semaphore

Semaphore的使用队列实现。xSemaphore的Give和Task分别向队列中存和从队列中取。

1.xSemaphoreGive

进入关键区之后,如果队列不为空,则立即切换进程。从注释可以看出,这里有两种实现:a.立即切换进程;b.这里只记录状态,在退出关键区时执行切换。这个跟port的实现有关,跟FreeRTOS无关。

另外,这里也不一定会切换进程,跟进程的优先级有关。如果等待信号量的进程优先级比当前进程优先级低,则不会进行切换。这里我们假设会切换。

2.xSemaphoreTake

如果队列为空则在箭头处睡眠等待。同时,队列被存入元素后,也是在这里被唤醒。唤醒后,执行如下代码检查队列是否为空:

可以看到,这里又重新执行了一次taskENTER_CRITICAL(),取得队列元素之后,退出时又执行了一次taskEXIT_CRITICAL(),这是成对的操作。所以不存在被切入的进程打开进程切换前关闭的中断的情况。

问题没有解决:中断时何时被打开的?

三.中断嵌套实现

FreeRTOS自带的例子中,有两种实现。

1.自定义嵌套层级变量

2.使用TCB中的嵌套层级变量

即直接使用FreeRTOS的vTaskEnterCritical/vTaskExitCritical,这两个函数:

两个的区别在于一个使用全局变量,一个使用每TASK变量存储中断嵌套层级。

为什么每一个TASK一个中断嵌套层级呢?

四.谁的中断嵌套层级

按常规的理解,中断属于CPU,而不属于TASK,一个CPU上可以有多个TASK在执行。而CPU是全局的,所以中断状态也应该是全局的,所以中断嵌套层级也应该使用全局变量存储。

每个TASK一个中断嵌套层级,如何理解?

我们知道每个TASK记录自己的各个寄存器的值,是可以理解的。以便切入时恢复之前的状态。难道每个TASK也维护执行时中断状态,以便切入时恢复执行?难道每个TASK也记录中断的开关状态,切入时恢复之前的中断开关状态?

看一下TASK切换时保存和恢复的寄存器,以PowerPC为例。

五.中断发生时保存和恢复的寄存器状态

SRR1中保存着中断发生前的MSR寄存器的值,也包括EE位。那么恢复时,自然也会恢复EE位。

六.总结

首先回答何时打开中断的问题:进程切入时,即恢复进程切出前的中断开关状态。

另外一个结论:中断状态在物理上虽然是全局的,但在软件上是每个TASK维护一份。

PS. 复杂度还是提升了,OS层需要加倍小心,好在APP层无需过多考虑。

原文地址:https://www.cnblogs.com/wjcdx/p/9388330.html

时间: 2024-11-09 01:57:28

FreeRTOS-为什么关中断之后切换进程?的相关文章

windbg-.process切换进程(内核)

.process .process 命令指定要用作进程上下文的进程(Set Process Context) .process显示当前进程的EPROCESS,这里显示当前进程为test.exe [cpp] view plain copy print? kd> .process Implicit process is now 821f5da0 kd> ? @$proc Evaluate expression: -2111873632 = 821f5da0 kd> !process 821f

编写一个stm32 svc关中断函数

做到了让stm32触发svc中断并传递进去参数然后切换到handler模式并修改特殊寄存器的值,从而达到关中断,但是其实这个程序直接就是特权级,故不进入handler模式也可以修改特殊寄存器...... 如下为调用写的开关中断函数: 新建了一个文件asm.c,所有我写的汇编函数都在里面: 前两个是关中断和开中断函数,主要做的事将参数传入R8并触发svc中断. Svc中断中则调用第三个set_i()函数. 当触发了中断之后,M3内核进入handler模式,利用R8中的数据,修改特殊寄存器BASEP

FreeRTOS高级篇4---FreeRTOS任务切换分析

FreeRTOS任务相关的代码大约占总代码的一半左右,这些代码都在为一件事情而努力,即找到优先级最高的就绪任务,并使之获得CPU运行权.任务切换是这一过程的直接实施者,为了更快的找到优先级最高的就绪任务,任务切换的代码通常都是精心设计的,甚至会用到汇编指令或者与硬件相关的特性,比如Cortex-M3的CLZ指令.因此任务切换的大部分代码是由硬件移植层提供的,不同的平台,实现发方法也可能不同,这篇文章以Cortex-M3为例,讲述FreeRTOS任务切换的过程. FreeRTOS有两种方法触发任务

操作系统,进程理论

一 为什么要有操作系统 (两本书:现代操作系统.操作系统原理) 现代的计算机系统主要是由一个或者多个处理器,主存,硬盘,键盘,鼠标,显示器,打印机,网络接口及其他输入输出设备组成. 一般而言,现代计算机系统是一个复杂的系统. 其一:如果每位应用程序员都必须掌握该系统所有的细节,那就不可能再编写代码了(严重影响了程序员的开发效率.) 其二:并且管理这些部件并加以优化使用,是一件极富挑战性的工作,于是,计算安装了一层软件(系统软件),称为操作系统.它的任务就是为用户程序提供一个更好.更简单.更清晰的

操作系统详解

一 为什么要有操作系统 (两本书:现代操作系统.操作系统原理,学好python以后再去研究吧~~) 现代的计算机系统主要是由一个或者多个处理器,主存,硬盘,键盘,鼠标,显示器,打印机,网络接口及其他输入输出设备组成. 一般而言,现代计算机系统是一个复杂的系统. 其一:如果每位应用程序员都必须掌握该系统所有的细节,那就不可能再编写代码了(严重影响了程序员的开发效率:全部掌握这些细节可能需要一万年....) 其二:并且管理这些部件并加以优化使用,是一件极富挑战性的工作,于是,计算安装了一层软件(系统

网络变成操作系统详解

一 为什么要有操作系统 (两本书:现代操作系统.操作系统原理,学好python以后再去研究吧~~) 现代的计算机系统主要是由一个或者多个处理器,主存,硬盘,键盘,鼠标,显示器,打印机,网络接口及其他输入输出设备组成. 一般而言,现代计算机系统是一个复杂的系统. 其一:如果每位应用程序员都必须掌握该系统所有的细节,那就不可能再编写代码了(严重影响了程序员的开发效率:全部掌握这些细节可能需要一万年....) 其二:并且管理这些部件并加以优化使用,是一件极富挑战性的工作,于是,计算安装了一层软件(系统

Linux进程调度(3):进程切换分析

3.调度函数schedule()分析 当kernel/sched.c:sched_tick()执行完,并且时钟中断返回时,就会调用kernel/sched.c:schedule()完成进程切换.我们也可以显示调用schedule(),例如在前面"Linux进程管理"的介绍中,进程销毁的do_exit()最后就直接调用schedule(),以切换到下一个进程. schedule()是内核和其他部分用于调用进程调度器的入口,选择哪个进程可以运行,何时将其投入运行.schedule通常都和一

FreeRTOS 临界段和开关中断

临界段代码的临界段也称为临界区,一旦这部分代码开始执行,则不允许任何中断打断.为确保临界段代码的执行不被中断,在进入临界段之前须关中断,而临界段代码执行完毕后,要立即开中断. FreeRTOS 临界段相关知识补充FreeRTOS 的源码中有多处临界段的地方, 临界段虽然保护了关键代码的执行不被打断, 但也会影响系统的实时性.比如此时某个任务正在调用系统 API 函数,而且此时中断正好关闭了,也就是进入到了临界区中,这个时候如果有一个紧急的中断事件被触发,这个中断就不能得到及时执行,必须等到中断开

实验八——理解进程调度时机跟踪分析进程调度与进程切换的过程

理解进程调度时机跟踪分析进程调度与进程切换的过程 攥写人:李鹏举  学号:20132201 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000) 一.实验要求: 理解Linux系统中进程调度的时机,可以在内核代码中搜索schedule()函数,看都是哪里调用了schedule(),判断我们课程内容中的总结是否准确: 使用gdb跟踪分析一个schedule()函数 ,验