一. 基本问题
 
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层无需过多考虑。

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

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

    .process .process 命令指定要用作进程上下文的进程(Set Process Context) .process显示当前进程的EPROCESS,这里显示当前进程为test.exe kd& ...

  2. 编写一个stm32 svc关中断函数

    做到了让stm32触发svc中断并传递进去参数然后切换到handler模式并修改特殊寄存器的值,从而达到关中断,但是其实这个程序直接就是特权级,故不进入handler模式也可以修改特殊寄存器..... ...

  3. 结合中断上下文切换和进程上下文切换分析Linux内核的一般执行过程

    结合中断上下文切换和进程上下文切换分析Linux内核的一般执行过程 目录 结合中断上下文切换和进程上下文切换分析Linux内核的一般执行过程 一. 实验准备 二. 实验过程 I 分析中断上下文的切换 ...

  4. 未关中断情况下的hardlock

    最近遇到一例crash,3.10内核,hardlock,查看对应的堆栈,中断是使能的. 查看对应的hrtimer_interrupts和hrtimer_interrupt_save的值,发现确实相等. ...

  5. linux的可中断sleep_on函数分析

    void interruptible_sleep_on (struct task_struct **p)// **p是个全局变量 { struct task_struct *tmp; if (!p)# ...

  6. (笔记)Linux内核学习(一)之内核介绍

    内核与操作系统: 内核是操作系统的核心部分,包含了系统运行的核心过程,决定系统的性能,操作系统启动内核被装入到RAM中: 操作系统与底层硬件设备交互和为运行应用程序提供执行环境. Linux内核与微内 ...

  7. 13 . Python3之并发编程

    什么是操作系统? 为什么要有操作系统? 现代的计算机系统主要是由一个或者多个处理器,主存,硬盘,键盘,鼠标,显示器,打印机,网络接口及其他输入输出设备组成. 一般而言,现代计算机系统是一个复杂的系统. ...

  8. 译<容器网络中OVS-DPDK的性能>

    译<容器网络中OVS-DPDK的性能> 本文来自对Performance of OVS-DPDK in Container Networks的翻译. 概要--网络功能虚拟化(Network ...

  9. FreeRTOS 临界段和开关中断

    以下转载自安富莱电子: http://forum.armfly.com/forum.php 临界段代码的临界段也称为临界区,一旦这部分代码开始执行,则不允许任何中断打断.为确保临界段代码的执行不被中断 ...

随机推荐

  1. js上传文件过大导致上传失败原因以及解决办法

    背景:项目需要用到上传视频功能,由于视频有知识产权,要求必须上传到自己的服务器上不允许用第三方视频网站接口上传,于是一开始开始用的是input type=file去上传,小的视频上传没有问题,上传将近 ...

  2. 10_CSS入门和高级技巧(8)

    图片透明 先来复习一下盒子的透明问题: opacity:0.6; 介于0~1之间,为了让IE兼容,我们要使用IE自己的滤镜: filter:alpha(opacity=60); 盒子的透明,会让里面的 ...

  3. 写了shell脚本想一键启动三台虚拟机的Zookeeper,却不知道为啥总是启动不了

    首先,一键启动的shell脚本是这样的 #! /bin/bash case $1 in "start"){ for i in node01 node02 node03 do ssh ...

  4. Day_08【面向对象】扩展案例1_测试项目经理类和程序员类

    分析以下需求,并用代码实现: 1.定义项目经理类 属性: 姓名 工号 工资 奖金 行为: 工作work 2.定义程序员类 属性: 姓名 工号 工资 行为: 工作work 要求: 向上抽取一个父类,让这 ...

  5. Linux内核驱动学习(七)应用层直接操作GPIO

    文章目录 简介 原理图 节点 设置为输出 设置为输入 映射关系 debugfs pwm demo 简介 前面通过libgpio的方式介绍了内核空间对GPIO进行操作的接口,其做了较好的封装,同时Lin ...

  6. 关于Fragment的点击切换数据滞留问题

    场景再现:当我使用tabLayout + Fragment 切换不同的fragment时,出现了数据重复显示的问题: 思考逻辑: - 每次切换fragment都会重新获取数据,但是list集合是全局的 ...

  7. jconsole+idea监控+(jvisualvm 本地内存分析)

    1.idea启动配置 添加以下内容 -Djava.rmi.server.hostname=127.0.0.1 -Dcom.sun.management.jmxremote -Dcom.sun.mana ...

  8. c#word文档输出

    在工作中有时需要把内容用word文档展示出来 在写代码前要引用word的dll Microsoft.Office.Interop.Word“ sing System; using System.Col ...

  9. Angular核心概念之五---过滤器

    Filter:过滤器,用于在view中呈现数据时显示为另一种格式:过滤器的本质是一个函数,接收原始数据转换为新的格式进行输出: function(oldVal){ ... return newVal ...

  10. 4.3 Go for

    4.3 Go for Go的for循环是一个循环控制结构,可以执行循环次数. 语法 package main import "fmt" func main() { //创建方式一, ...