基于嵌入式操作系统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);

总的来说,在实时系统中采取“禁止中断”的方法会影响系统对外部中断及时响应和处理的能力;而“禁止优先级抢占调度”方法阻止了高优先级的任务抢先运行,在实时系统中也是不适合的。因此,信号量无疑是解决互斥问题的最好方法。

转载于:https://blog.51cto.com/21cnbao/120322

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

  1. 基于嵌入式操作系统VxWorks的多任务并发程序设计(4)――任务间通信A

    基于嵌入式操作系统VxWorks的多任务并发程序设计(4) ――任务间通信 作者:宋宝华  e-mail:[email]21cnbao@21cn.com[/email] 出处:软件报 VxWorks提 ...

  2. 基于嵌入式操作系统VxWorks的多任务并发程序设计(3)――任务调度

    基于嵌入式操作系统VxWorks的多任务并发程序设计(3) ――任务调度 作者:宋宝华  e-mail:[email]21cnbao@21cn.com[/email] 出处:软件报 VxWorks支持 ...

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

    中断处理是整个运行系统中优先级最高的代码,可以抢占任何任务级代码运行.中断机制是多任务环境运行的基础,是系统实时性的保证.几乎所有的实时多任务操作系统都需要一个周期性系统时钟中断的支持,用以完成时间片 ...

  4. 嵌入式操作系统VxWorks中网络协议存储池原理及实现

    嵌入式操作系统VxWorks中网络协议存储池原理及实现 周卫东 蔺妍 刘利强 (哈尔滨工程大学自动化学院,黑龙江 哈尔滨,150001) 摘  要  本文讨论了网络协议存储池的基本原理和在嵌入式操作系 ...

  5. 计算机操作系统(八)——并发程序设计

    并发程序设计 顺序程序设计 进程的并发执行 处理器利用率计算 并发程序设计 把一个具体问题求解设计成若干个可同时执行的程序模块的方法 特性: 无关与交往的并发进程 与时间有关的错误 进程互斥与进程同步 ...

  6. 嵌入式linux程序加密,基于嵌入式操作系统uClinux实现网络安全加密系统的设计

    金融安全支付系统是专门针对金融领域应用需求,实现小型化.便捷.安全的自助交易的软硬件平台,能够为多种应用提供高速安全服务,解决目前交易信息在传输过程中存在的各种安全问题,实现金融信息的安全交易.基于该 ...

  7. 嵌入式操作系统VxWorks简介

    出处:http://www.embhelp.com/drew/mypage/VxWorks.htm VxWorks操作系统是美国WindRiver公司于1983年设计开发的一种嵌入式实时操作系统(RT ...

  8. 操作系统实验一:并发程序设计

    一.实验目的 (1)加深对进程并发执行的理解,认识多进程并发执行的实质. (2)观察进程共享资源的现象,学习解决进程互斥和同步的方法. 二.实验要求: 本实验要求用高级语言,启动多进程并发运行,设计相 ...

  9. Niobe开发板:基于OpenHarmony操作系统进行多线程(多任务)开发

    线程的基本概念 从系统角度看,线程是竞争系统资源的最小运行单元.线程可以使用或等待CPU.使用内存空间等系统资源,并独立于其它线程运行. OpenHarmony LiteOS可以给用户提供多个线程,实 ...

最新文章

  1. 索尼搞了个大新闻!AI打败人类三冠王,登上Nature封面,这波让任天堂无话可说...
  2. Windows下sc create命令行添加/创建/修改服务
  3. java 线程的几种状态(转载)
  4. eureka需要替换吗_Spring Cloud Alibaba迁移指南1:零代码从Eureka迁移到Nacos
  5. activiti5第六弹 手动任务、接收任务、邮件任务
  6. 贪心算法——找纸币问题
  7. [转]Windows Shell 编程 第八章 【来源:http://blog.csdn.net/wangqiulin123456/article/details/7987961】...
  8. 稀疏表示(Sparse Representations)
  9. Google永久允许使用Flash 100%详细简单+解决
  10. 第4章内容-启动豆果美食并抓包
  11. 【节能学院】剩余电流动作继电器在浴室中的应用
  12. 中国图书分类法检索计算机方面的图书,《中国图书分类法》(简称《中图法》)是我国常用的分类法,要检索计算机方面的图书,需要在( )类目下查找。...
  13. iPhone转Android体验,从苹果转安卓之后的一点体验,供大家参考
  14. 使用R/qtl进行QTL分析
  15. flink ui含义图解
  16. 【原创】2012年3月24日 单骑至大峪 日志
  17. 2021海南高考成绩排名查询,海南高考排名查询方法,2021年海南高考成绩位次全省排名查询...
  18. python人民币金额转汉字大写
  19. canal kafka camus整合
  20. 深入分析eBay卖家打造爆款的痛点:如何选品才有机会打造爆款?

热门文章

  1. BP神经网络:feedforwardnet版回归预测
  2. MATLAB 读取文件数据(txt)
  3. matlab堆栈的思想,[转载]Matlab源代码:堆栈类Stack的实现
  4. java的程序编码_Java 程序编码规范(初学者要牢记)
  5. 计算机图形学前沿领域的设想,计算机图形学
  6. activator.createinstance 需要垃圾回收么_Epsilon:你为什么需要一个不回收内存的垃圾回收器?...
  7. linux mysql查看数据库编码_MySQL查看和修改字符编码的实现方法
  8. mac 本地安装mysql_mac 本地安装mysql服务
  9. 数据库java_(六) Java数据库
  10. mex 里面调用matlab函数