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

简介:
基于嵌入式操作系统 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 寄存器  */
  
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);

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




 本文转自 21cnbao 51CTO博客,原文链接:http://blog.51cto.com/21cnbao/120322,如需转载请自行联系原作者




相关文章
|
12月前
|
安全 Unix Linux
Unix是一个多用户、多任务的操作系统
Unix是一个多用户、多任务的操作系统
502 3
|
Web App开发 Linux iOS开发
操作系统的演变:从单任务到多核并发
在数字时代的浪潮中,操作系统作为计算机硬件与应用程序之间的桥梁,其发展历史充满了创新与变革。本文将带领读者穿越时空,探索操作系统如何从简单的单任务处理演化为今天能够高效管理多核处理器的复杂系统。我们将一窥各个时代下操作系统的设计哲学,以及它们是如何影响现代计算的方方面面。加入我们的旅程,一起见证技术的力量如何在每次迭代中重塑世界。
124 7
|
人工智能 算法 数据挖掘
操作系统的演变:从单任务到多任务的旅程
操作系统(OS)是计算机系统的核心,它管理硬件资源、提供用户界面并运行应用程序。本文将探讨操作系统如何从单任务环境演变为支持多任务的环境,包括这一过程中的技术挑战和解决方案。我们将看到,随着计算需求的增长,操作系统必须适应更复杂的任务管理和资源分配策略,以提高效率和用户体验。通过这个旅程,我们不仅能够理解操作系统的发展,还能洞察未来可能的趋势。
110 5
|
机器学习/深度学习 人工智能 算法
操作系统的未来:从多任务到深度学习的演变之路
本文将探讨操作系统如何从处理简单多任务发展到支持复杂的深度学习任务。我们将分析现代操作系统面临的新挑战,以及它们如何适应人工智能和大数据时代的要求。文章不仅回顾过去,也展望未来,思考操作系统在技术演进中的角色和方向。
175 3
|
机器学习/深度学习 人工智能 安全
操作系统的未来:从多任务处理到人工智能
【8月更文挑战第23天】本文将探讨操作系统的发展历程及其未来趋势,特别是人工智能在操作系统中的应用。我们将看到如何通过引入人工智能技术,操作系统能够更加智能化地管理资源,提高系统性能和用户体验。
|
11月前
|
存储 iOS开发 MacOS
MacOS环境-手写操作系统-33-多任务多窗口
MacOS环境-手写操作系统-33-多任务多窗口
113 0
|
缓存 安全 数据库
探索后端开发的核心原则与实践操作系统的未来:从多任务处理到智能优化
【8月更文挑战第23天】在数字化时代的浪潮中,后端开发作为技术架构的支柱,承载着数据处理、业务逻辑实现和系统性能优化的关键任务。本文将深入探讨后端开发的几大核心原则,包括模块化设计、性能优化、安全性强化及可维护性提升,旨在为读者揭示如何构建一个健壮、高效且安全的后端系统。通过分析这些原则背后的理念及其在实际开发中的应用,本文意在启发读者思考如何在不断变化的技术环境中,持续优化后端开发实践,以适应新的挑战和需求。
|
调度 UED
操作系统中的多任务处理机制
【8月更文挑战第23天】在数字时代,操作系统的核心功能之一是多任务处理。它允许用户同时运行多个程序,优化资源使用,并提高生产效率。本文将深入探讨操作系统如何实现多任务处理,以及这一机制对用户体验和系统性能的影响。通过理解多任务处理的工作原理,用户可以更好地管理计算资源,提升个人和组织的工作效率。
|
人工智能 算法 物联网
操作系统的演变:从单任务到多任务的旅程
【8月更文挑战第20天】在数字时代的浪潮中,操作系统作为计算机系统的核心,经历了从简单的单任务处理到复杂的多任务并行处理的转变。本文将探讨这一转变过程中的关键里程碑,包括早期的批处理系统、多道程序设计的出现、分时系统的创新以及现代操作系统中的多任务处理机制。通过这一旅程,我们将了解操作系统如何适应不断增长的计算需求,并预见未来可能的发展方向。
|
机器学习/深度学习 人工智能 自动驾驶
操作系统的演化之路:从单任务到多任务处理
【8月更文挑战第16天】 本文将探索操作系统(OS)的演进历程,聚焦于它们如何从处理单一任务的简单系统,发展成为能够同时处理多个任务的复杂系统。我们将分析这一转变背后的技术驱动因素,以及它对用户体验和系统性能的影响。文章还将探讨现代操作系统在面对日益增长的计算需求时所面临的挑战,以及未来的发展方向。

热门文章

最新文章

推荐镜像

更多