基于嵌入式操作系统VxWorks的多任务并发程序设计(5)――中断与任务

2023-05-16

基于嵌入式操作系统 VxWorks 的多任务并发程序设计( 5
――中断与任务
作者:宋宝华  e-mail:[email]21cnbao@21cn.com[/email]  出处:软件报
中断处理是整个运行系统中优先级最高的代码,可以抢占任何任务级代码运行。中断机制是多任务环境运行的基础,是系统实时性的保证。几乎所有的实时多任务操作系统都需要一个周期性系统时钟中断的支持,用以完成时间片调度和延时处理。 VxWorks 提供 tickAnnounce() ,由系统时钟中断调用,周期性地触发内核。
为了快速响应中断, VxWorks 的中断服务程序( ISR )运行在特定的空间。不同于一般的任务,中断服务程序没有任务上下文,不包含任务控制块,所有的中断服务程序使用同一中断堆栈,它在系统启动时就已根据具体的配置参数进行了分配和初始化。在 ISR 中能使用的函数类型与在一般任务中能使用的有些不同,主要体现在:
1 ISR 中不能调用可能导致 blocking 的函数,例如:
(a) 不能以 semTake 获取信号量,因如果该信号量不可利用,内核会试图让调用者切换到 blocking 态;
(b)malloc free 可能导致 blocking ,因此也不能使用;
(c) 应避免进行 VxWorks I/O 系统操作(除管道外);
(d) 应避免在 ISR 中进行浮点操作。
2 )在 ISR 中应以 logMsg 打印消息,避免使用 printf
3 )理想的 ISR 仅仅调用 semGive 等函数,其它的事情交给 semTake 这个信号量的任务去做。一个 ISR 通常作为通信或同步的发起者,它采用发送信号量或向消息队列发送一个消息的方式触发相关任务至就绪态。 ISR 几乎不能作为信息的接收者,它不可以等待接收消息或信号量。

11.中断服务程序

VxWorks 中与中断相关的重要 API 函数或宏有:
1 intConnect() :中断连接,将中断向量与 ISR 入口函数绑定
SYNOPSIS STATUS intConnect
     (
       VOIDFUNCPTR *  vector,/* interrupt vector to attach to    */
       VOIDFUNCPTR    routine, /* routine to be called         */
       int        parameter /* parameter to be passed to routine */
      );
intConnect 只是调用了下文将要介绍的 intHandlerCreate() intVecSet() 函数。
2 INUM_TO_IVEC(intNum) :将中断号转化为中断向量的宏。与 INUM_TO_IVEC 对应的还有一个 IVEC_TO_INUM(intVec) ,实现相反的过程。 INUM_TO_IVEC IVEC_TO_INUM 的具体定义与特定的 BSP 有关,例如:
/* macros to convert interrupt vectors <-> interrupt numbers */
#define IVEC_TO_INUM(intVec)    ((int) (intVec))
#define INUM_TO_IVEC(intNum)    ((VOIDFUNCPTR *) (intNum))
结合 1 2 可知一般挂接一个中断服务程序的调用为:
intConnect(INUM_TO_IVEC(INTERRUPT_LEVEL),(VOIDFUNCPTR)interruptHandler,i);

1:中断服务程序  
/* includes */
#include "vxWorks.h"
#include "intLib.h"
#include "taskLib.h"
#include "sysLib.h"
#include "logLib.h"
 
/* function prototypes */
void interruptHandler(int);
void interruptCatcher(void);
 
/* globals */
#define INTERRUPT_NUM 2
#define INTERRUPT_LEVEL 65
#define ITER1 40
#define LONG_TIME 1000000
#define PRIORITY 100
#define ONE_SECOND 100
 
void interruptGenerator(void) /* task to generate the SIGINT signal */
{
  int i, j, taskId, priority;
  STATUS taskAlive;

  
 
  if ((taskId = taskSpawn("interruptCatcher", PRIORITY, 0x100, 20000, (FUNCPTR)
    interruptCatcher, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
    logMsg("taskSpawn interruptCatcher failed\n", 0, 0, 0, 0, 0, 0);
 
  for (i = 0; i < ITER1; i++)
  {
    taskDelay(ONE_SECOND); /* suspend interruptGenerator for one second */
    /* check to see if interruptCatcher task is alive! */
    if ((taskAlive = taskIdVerify(taskId)) == OK)
    {
      logMsg("++++++++++++++++++++++++++Interrupt generated\n", 0, 0, 0, 0, 0,
        0);
      /* generate hardware interrupt 2 */
      if ((sysBusIntGen(INTERRUPT_NUM, INTERRUPT_LEVEL)) == ERROR)
        logMsg("Interrupt not generated\n", 0, 0, 0, 0, 0, 0);
    }
    else
     /* interruptCatcher is dead */
      break;
  }
  logMsg("\n***************interruptGenerator Exited***************\n\n\n\n", 0,
    0, 0, 0, 0, 0);
}
 
void interruptCatcher(void) /* task to handle the interrupt */
{
  int i, j;
  STATUS connected;
 
  /* connect the interrupt vector, INTERRUPT_LEVEL, to a specific interrupt
  handler routine ,interruptHandler,  and pass an argument, i */
  if ((connected = intConnect(INUM_TO_IVEC(INTERRUPT_LEVEL), (VOIDFUNCPTR)
    interruptHandler, i)) == ERROR)
    logMsg("intConnect failed\n", 0, 0, 0, 0, 0, 0);
 
  for (i = 0; i < ITER1; i++)
  {
    for (j = 0; j < LONG_TIME; j++)
      ;
    logMsg("Normal processing in interruptCatcher\n", 0, 0, 0, 0, 0, 0);
  }
  logMsg("\n+++++++++++++++interruptCatcher Exited+++++++++++++++\n", 0, 0, 0,
    0, 0, 0);
}
 
void interruptHandler(int arg) /* signal handler code */
{
  int i;
 
  logMsg("-------------------------------interrupt caught\n", 0, 0, 0, 0, 0, 0);
  for (i = 0; i < 5; i++)
    logMsg("interrupt processing\n", 0, 0, 0, 0, 0, 0);
}
程序中的 sysBusIntGen() 调用将产生一个 bus 中断,这个函数与特定的 BSP 密切相关,其原型为:
STATUS sysBusIntGen
(
int intLevel, /* bus interrupt level to generate */
int vector /* interrupt vector to generate (0-255) */
);
为了在同一中断源的几种中断服务程序中进行切换,我们应使用如下方式:
vector = INUM_TO_IVEC(some_int_vec_num);
oldfunc = intVecGet (vector);
newfunc = intHandlerCreate (routine, parameter);
intVecSet (vector, newfunc);
...
intVecSet (vector, oldfunc); /* use original routine */
...
intVecSet (vector, newfunc); /* reconnect new routine */
其中, intHandlerCreate 函数的原型为:
FUNCPTR intHandlerCreate
(
FUNCPTR routine, /* routine to be called */
int parameter /* parameter to be passed to routine */
);
它被用于创建一个中断服务程序,在此之后,通过 intVecSet() 函数我们就可以将 intHandlerCreate() 创建的结果与中断向量绑定, intVecSet() 函数的原型为:
void intVecSet
(
FUNCPTR * vector, /* vector offset */
FUNCPTR function /* address to place in vector */
);

12.中断控制

12.1中断执行过程

硬件中断发生时,代码运行的上下文会发生切换,在进入中断处理前,需要保存当前运行的上下文。对于一些无 RTOS 的单片机系统,这些工作由硬件和编译器共同完成,向量表在编译完成后就填充完成,再写入存储器中,系统运行时不能修改向量表来重新绑定中断入口函数。在 VxWorks 系统中,除了需要保存通常的寄存器环境外,还需要完成栈切换等;另外还要求中断入口运行时绑定、平台移植性、中断嵌套等,所以 VxWorks 本身也参与中断封装的管理。 VxWorks 进行中断封装的伪代码如下:
* 00  e8 kk kk kk kk call  _intEnt * 通知内核
* 05  50   pushl %eax  * 保存寄存器
* 06  52   pushl %edx
* 07  51   pushl %ecx
* 08  68 pp pp pp pp pushl $_parameterBoi * push BOI param
* 13  e8 rr rr rr rr call  _routineBoi  * call BOI routine
* 18  68 pp pp pp pp pushl $_parameter  * 传中断入口参数
* 23  e8 rr rr rr rr call  _routine   * 调用中断处理 C 函数
* 28  68 pp pp pp pp pushl $_parameterEoi * push EOI param
* 33  e8 rr rr rr rr call  _routineEoi  * call EOI routine
* 38  83 c4 0c  addl  ?, %esp   * pop param
* 41  59   popl  %ecx  * 恢复寄存器
* 42  5a   popl  %edx
* 43  58   popl  %eax
* 44  e9 kk kk kk kk jmp  _intExit * 通过内核退出

12.2中断使能/禁止

VxWorks 提供两个重要 API
1 intLock() :使中断禁止
2 intUnlock() :开中断
可以用 intLock/intUnlock 提供最高级别的互斥机制以保护临界区域不被打断,例如:
oldlevel = intLock();
/* XXX 寄存器 */
XXX_REG_WRITE(pChan, XXX_UBRDIV, XXX_CNT0_115200 |  XXX_CNT1_VAL); 
intUnlock(oldlevel);
intLock() 禁止中断后,当前执行的任务将一直继续,中断处理和任务调度得不到执行,直到该任务主动调用 intUnLock 解锁中断为止。对于 intLock unLock 的使用,我们要注意如下几点:
1 )不要在中断禁止期间调用 vxWorks 系统函数,否则有可能意外使能中断,违反临界代码的设计意图。另外, intLock 也不能屏蔽调度,如果在中断禁止代码区使用系统调用,就可能出现任务调度,其他任务的运行可能会解锁中断;
2 )中断禁止对系统的实时性有很大的影响,在解决执行代码和中断处理互斥问题才可使用,并且应使中断禁止时间尽可能的短。对于任务间的互斥问题,可以使用 taskLock() taskUnLock() 来解决;
3 )有些 CPU 中断是分级,我们可以用 intLockLevelSet() intLockLevelGet() 来操作中断闭锁的级别。缺省情况下, taskLock 禁止所有等级的中断。
至此,我们可以对“互斥”问题进行一个系统的总结,主要有如下几种方法:
1 intLock 禁止中断:解决任务和 ISR 之间的互斥问题;
  int lock = intLock();
  //. . critical region that cannot be interrupted
  intUnlock(lock);
2 taskLock 禁止优先级抢占调度:当当前任务正在运行时,除了中断服务程序外,高优先级的任务也不允许抢占 CPU
  taskLock();
  //. . critical region that cannot be interrupted .
  taskUnlock();
3 )二进制信号量或互斥信号量。
semTake (semMutex, WAIT_FOREVER);
  //. . critical region, only accessible by a single task at a time .
semGive (semMutex);
总的来说,在实时系统中采取“禁止中断”的方法会影响系统对外部中断及时响应和处理的能力;而“禁止优先级抢占调度”方法阻止了高优先级的任务抢先运行,在实时系统中也是不适合的。因此,信号量无疑是解决互斥问题的最好方法。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于嵌入式操作系统VxWorks的多任务并发程序设计(5)――中断与任务 的相关文章

  • 基于vue解决大数据表格卡顿问题

    点我在线体验Demo 请用电脑查看 亲测苹果电脑 xff0c chrome浏览器无卡顿现象 xff0c 其它浏览器并未测试 xff0c 如遇到卡顿请备注系统和浏览器 xff0c 方便我后续优化 xff0c 谢谢 先看一下效果 一共1000
  • raid1损坏一块盘之后的处理方式

    在企业生产环境中 xff0c 假如raid1两块盘中的一块损坏了 xff0c 后续如何处理 xff1f 直接换下损坏的磁盘是否会对服务有影响 xff08 如何把影响降到最低 xff09 xff0c 加入新的磁盘后是否还需要重新做raid1
  • Landsat Tm5辐射定标和大气校正(转)

    一 辐射定标 1 由于ENVI 4 4 中有专门进行辐射定标的模块 xff0c 因此实际的操作十分简单 将原始TM 影像打开以后 xff0c 选择 Basic Tools Preprocessing Calibration Utilitie
  • Traversing the Dept Security tree

    We can use the connect by prior function provided by Oracle to traverse the Dept security Tree Suppose an Organization h
  • Reconfigurable computing[可重构计算]

    在实验室跟老师做一些硬件加速相关的东西 xff0c 看文献时看到Reconfigurable computing xff0c 发现这个很有意思 现在每天都有越来越多的数据产生 xff0c 要处理这些数据如果单纯用CPU计算的话会耗费很多时间
  • 嵌入式作业STM32采用串口DMA方式发送数据

    目录 前言 要求 一 DMA的基本介绍 DMA的基本定义 DMA的主要特征 STM32F411x系列芯片DMA控制器 二 通过CubeMX配置项目 1 创建项目 2 选择芯片STM32F103C8T6 3 设置RCC 4 设置串口 5 设置
  • C ~ char int 等数据转换问题

    1 xff0c char型数字转换为int型 char a 61 34 32 34 printf 34 d n 34 a 0 39 0 39 输出结果为3 2 xff0c int转化为char 1 字符串转换成数字 xff0c 用atoi
  • curl get请求添加header头信息

    function get url ch 61 curl init curl setopt ch CURLOPT HTTPGET true curl setopt ch CURLOPT RETURNTRANSFER 1 TRUE 将curl
  • 关于 RESTFUL API 安全认证方式的一些总结

    常用认证方式 在之前的文章 REST API 安全设计指南 与 使用 AngularJS amp NodeJS 实现基于 token 的认证应用 两篇文章中 xff0c 译 web权限验证方法说明 中也详细介绍 xff0c 一般基于REST
  • C++ REST SDK的基本用法

    微软开发了一个开源跨平台的http库 C 43 43 REST SDK xff08 http casablanca codeplex com xff09 xff0c 又名卡萨布兰卡Casablanca xff0c 有个电影也叫这个名字 xf
  • ubuntu下socket通信

    之前的博文介绍了如何在ubuntu下实现unix domain socket通信 xff0c 但只是本地的通信 xff0c 虽然过程和网络通信很类似 xff0c 但这里还是有必要了解下真正的socket通信 首先贴出server端的c代码
  • c语言中宏定义中void,C语言中宏定义几道问题!

    C语言中宏定义几道问题 xff01 答案 1 信息版本 xff1a 手机版 解决时间 2020 04 27 20 44 已解决 2020 04 27 17 15 一 执行下列程序 define MA x y x y k 61 5 k 61
  • IE浏览器自动配置脚本的使用(代理上网)

    以前在FireFox中设置过代理服务器自动配置脚本 xff0c 对于访问某些无法访问的网站非常有效 xff0c 在IE中应该也是有效的 xff0c 但是我配置了好几次都没有配置成功 xff0c 今天发现原来是格式错误 xff0c 修改了一下
  • c语言中通过指针将数值赋值到制定内存地址

    1 一种直观的方法 假设现在需要往内存0x12ff7c地址上存入一个整型数0x100 我们怎么才能做到呢 xff1f 我们知道可以通过一个指针 向其指向的内存地址写入 数据 xff0c 那么这里的内存地址0x12ff7c其本质不就是一个指针
  • 一个封装HTTP请求的函数(C++)

    这里封装 了HTTP请求的 xff0c 支持GET与POST xff0c 并支持各种参数组合 xff0c 调用方式很简单 使用DEVWEB WebRequest string http www luaie com ret 就可以了 如果使用
  • c++ vector 用法总结

    vector 是向量类型 xff0c 它可以容纳许多类型的数据 xff0c 如若干个整数 xff0c 所以称其为容器 vector 是C 43 43 STL的一个重要成员 xff0c 使用它时需要包含头文件 xff1a include lt
  • ubuntu命令行语法_HTTPie:超爽的HTTP命令行客户端

    之前在命令行下进行HTTP服务的调试和信息查看都是使用经典的cURL xff0c 不过前段时间发现一个交互更加友好的工具 xff0c 就是HTTPie 先放一个HTTPie官方的一个HTTPie VS cURL的图给大家看看 如果你经常需要
  • 如何用c语言串口通讯,串口通信入门

    在讲解本章的内容之前请大家先反复阅读 手把手教你学51单片机 文档的第11章内容 xff0c 很多概念文档都已详细讲解有 1 波特率 串口通信就是单片机与电脑端 xff0c 单片机与单片机 xff0c 单片机与模块器件之间互发信息进行通信
  • php和js区别

    php和js区别 两者在语法上类似 xff0c 楼上说的对 xff0c js 61 javascript是工作在浏览器端的脚本语言 xff0c 他所提交的数据是交给浏览器来处理的 但是现在的Ajax技术已经可以把js提交的数据交付到浏览器来
  • web前端利用turf.js生成等值线、等值面

    样例如下 xff1a lt DOCTYPE html gt lt html xmlns 61 34 http www w3 org 1999 xhtml 34 gt lt head gt lt meta http equiv 61 34 C

随机推荐

  • python模块名和文件名冲突解决

    对于python初学者 xff0c 很容易练习到一个随机数生成的程序 xff0c 代码如下 xff1a 1 usr bin python 2 import random 3 print random randint 12 20 这个小程序最
  • python3 logging 'ascii' codec can't encode characters

    环境 xff1a mac 10 12 python3 django 1 10 问题发现 最近刚从arch 换到 mac下搬砖 xff0c 发现在arch跑的好好的代码 xff0c 在mac下 终端老是报错 还是编码错误 code try i
  • Hutool之文件工具——FileUtil

    为什么80 的码农都做不了架构师 xff1f gt gt gt 简介 我想在Java工具中 xff0c 文件操作应该也是使用相当频繁的 xff0c 但是Java对文件的操作由于牵涉到流 xff0c 所以较为繁琐 xff0c 各种Stream
  • java中数字与ASCII码的相互转换

    2019独角兽企业重金招聘Python工程师标准 gt gt gt code 测试demo public static void main String args int a 61 91151561 for byte b String va
  • IDEA怎么查看现在的项目使用的JDK版本? 2016年4月19日22:51

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 右键单击项目 xff0c 选择 或者直接使用F4 转载于 https my oschina net sprouting blog 670222
  • 什么是北向接口和南向接口

    Northbound Interface Southbound Interface 南向接口 xff1a 管理其他厂家网管或设备的接口 xff0c 即向下提供的接口 北向接口 xff1a 提供给其他厂家或运营商进行接入和管理的接口 xff0
  • 官网下载mysql源码

    官网下载mysql源码 xff0c 如下为具体步骤 xff1a 1 进入官网点击download页https www mysql com downloads 2 点击MySQL Community Edition进入mysql社区版下载页面
  • Vue设置button的disable属性

    表单元素有一个disable属性 xff0c 用来控制该元素是否可用 1 这个属性在HTML里只有1个值 xff0c 用法就是 lt button disable 61 34 disable 34 gt 点击 lt button gt 经实
  • 用C++进行简单的文件I/O操作

    序论 我曾发表过文件输入输出的文章 xff0c 现在觉得有必要再写一点 文件 I O 在C 43 43 中比烤蛋糕简单多了 在这篇文章里 xff0c 我会详细解释ASCII和二进制文件的输入输出的每个细节 xff0c 值得注意的是 xff0
  • VC++鼠标画圈

    int r 61 100 int x0 61 gameRect left 43 pt x int y0 61 gameRect top 43 pt y int x y double n 61 0 MoveTo x0 y0 while n l
  • matlab练习程序(求向量间的旋转矩阵与四元数)

    问题是这样 xff0c 如果我们知道两个向量v1和v2 xff0c 计算从v1转到v2的旋转矩阵和四元数 xff0c 由于旋转矩阵和四元数可以互转 xff0c 所以我们先计算四元数 我们可以认为v1绕着向量u旋转 角度到v2 xff0c u
  • 用lighttpd搭建一个简易的http服务器

    1 安装lighttpd 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 cd wget http download lighttpd net lighttpd releases
  • 结构体(对齐规则及举例)

    概念 一种数据结构 xff1b C语言中聚合数据类型的一类 xff1b 可以被声明为变量 数组 指针等 xff0c 用以实现比较复杂的数据结构 xff1b 是一系列元素的集合 xff0c 这些元素被称为结构体成员 xff1b 结构体成员需要
  • C++解析头文件-Qt自动生成信号定义

    目录 一 概述二 实现思路三 代码讲解 1 类图2 QtCppDescription3 测试四 源代码 一 概述 上一篇文章C 43 43 解析头文件 Qt自动生成信号声明我们主要讲解了怎么去解析C 43 43 头文件 xff0c 然后在指
  • VC++6.0与VS2010的区别

    区别1 字符串的表达 void CMy123Dlg OnBnClickedButton1 MessageBox 34 你好 34 以前VC6 0写法 现在用不了 老版本用的多字节字符集 MessageBox L 34 你好 34 L 是 u
  • 存储过程出现ORA-06508错误

    一个存储过程平时执行正常 xff0c 刚才执行出ORA 06508错误 百思不得其解 xff0c 好像没有什么不正常的地方啊 xff01 后来找到了答案 重现这个错误如下 xff1a 执行一个存储过程 xff0c 其运行时间比较长 刚开始运
  • 从零构建TCP/IP协议

    从零构建TCP IP协议 这次叫PCT协议 这篇博客是读完 图解TCP IP协议 和 TCP IP协议详解卷一 xff1a 协议 之后的总结 我从0构建了一个可靠的双工的有序的基于流的协议 xff0c 叫做PCT协议 OSI七层模型和TCP
  • c语言 checksum,crc校验方法,用c语言实现源代码(CRC checksum method, using C language source code).doc...

    crc校验方法 用c语言实现源代码 CRC checksum method using C language source code crc校验方法 用c语言实现源代码 CRC checksum method using C languag
  • arm: 使用结构体操作寄存器

    使用结构体操作 寄存器 xff1a 寄存器赋值和取值的时候 xff0c 要注意寄存器的长度 xff0c 有的寄存器的值只有8位 还要注意 xff0c 使用volatile修饰寄存器变量 volatile 参考http www cnblogs
  • 基于嵌入式操作系统VxWorks的多任务并发程序设计(5)――中断与任务

    基于嵌入式操作系统 VxWorks 的多任务并发程序设计 xff08 5 xff09 中断与任务 作者 xff1a 宋宝华 e mail email 21cnbao 64 21cn com email 出处 xff1a 软件报 中断处理是整