日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

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

發布時間:2023/12/10 windows 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于嵌入式操作系统VxWorks的多任务并发程序设计――中断与任务 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

中斷處理是整個運行系統中優先級最高的代碼,可以搶占任何任務級代碼運行。中斷機制是多任務環境運行的基礎,是系統實時性的保證。幾乎所有的實時多任務操作系統都需要一個周期性系統時鐘中斷的支持,用以完成時間片調度和延時處理。VxWorks 提供tickAnnounce(),由系統時鐘中斷調用,周期性地觸發內核。

  為了快速響應中斷,VxWorks的中斷服務程序(ISR)運行在特定的空間。不同于一般的任務,中斷服務程序沒有任務上下文,不包含任務控制塊,所有的中斷服務程序使用同一中斷堆棧,它在系統啟動時就已根據具體的配置參數進行了分配和初始化。在ISR中能使用的函數類型與在一般任務中能使用的有些不同,主要體現在:

  (1ISR中不能調用可能導致blocking的函數,例如:

  (a)不能以semTake獲取信號量,因如果該信號量不可利用,內核會試圖讓調用者切換到blocking態;

  (b)mallocfree可能導致blocking,因此也不能使用;

  (c)應避免進行VxWorks I/O系統操作(除管道外);

  (d)應避免在ISR中進行浮點操作。

  (2)在ISR中應以logMsg打印消息,避免使用printf

  (3)理想的ISR僅僅調用semGive等函數,其它的事情交給semTake這個信號量的任務去做。一個ISR通常作為通信或同步的發起者,它采用發送信號量或向消息隊列發送一個消息的方式觸發相關任務至就緒態。ISR幾乎不能作為信息的接收者,它不可以等待接收消息或信號量。

  11.中斷服務程序

  VxWorks中與中斷相關的重要API函數或宏有:

  (1intConnect():中斷連接,將中斷向量與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()函數。

  (2INUM_TO_IVEC(intNum):將中斷號轉化為中斷向量的宏。與INUM_TO_IVEC對應的還有一個IVEC_TO_INUM(intVec),實現相反的過程。INUM_TO_IVECIVEC_TO_INUM的具體定義與特定的BSP有關,例如:

/* macros to convert interrupt vectors <-> interrupt numbers */
#define IVEC_TO_INUM(intVec)
  ((int) (intVec))
#define INUM_TO_IVEC(intNum)
  ((VOIDFUNCPTR *) (intNum))

  結合12可知一般掛接一個中斷服務程序的調用為:

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 failedn", 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 generatedn", 0, 0, 0, 0, 0,
  
    0);
  
   /* generate hardware interrupt 2 */
  
   if ((sysBusIntGen(INTERRUPT_NUM, INTERRUPT_LEVEL)) == ERROR)
  
    logMsg("Interrupt not generatedn", 0, 0, 0, 0, 0, 0);
  
  }
  
  else
  
   /* interruptCatcher is dead */
  
   break;
  
 }
  
 logMsg("n***************interruptGenerator Exited***************nnnn", 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 failedn", 0, 0, 0, 0, 0, 0);
  
 for (i = 0; i < ITER1; i++)
  
 {
  
  for (j = 0; j < LONG_TIME; j++)
  
   ;
  
  logMsg("Normal processing in interruptCatchern", 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 caughtn", 0, 0, 0, 0, 0, 0);
  
 for (i = 0; i < 5; i++)
  
  logMsg("interrupt processingn", 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

  (1intLock():使中斷禁止

  (2intUnlock():開中斷

  可以用intLock/intUnlock提供最高級別的互斥機制以保護臨界區域不被打斷,例如:

oldlevel = intLock();
/*
XXX寄存器 */
XXX_REG_WRITE(pChan, XXX_UBRDIV, XXX_CNT0_115200 |
 XXX_CNT1_VAL); 
intUnlock(oldlevel);

  用intLock()禁止中斷后,當前執行的任務將一直繼續,中斷處理和任務調度得不到執行,直到該任務主動調用intUnLock解鎖中斷為止。對于intLockunLock的使用,我們要注意如下幾點:

  (1)不要在中斷禁止期間調用vxWorks系統函數,否則有可能意外使能中斷,違反臨界代碼的設計意圖。另外,intLock也不能屏蔽調度,如果在中斷禁止代碼區使用系統調用,就可能出現任務調度,其他任務的運行可能會解鎖中斷;

  (2)中斷禁止對系統的實時性有很大的影響,在解決執行代碼和中斷處理互斥問題才可使用,并且應使中斷禁止時間盡可能的短。對于任務間的互斥問題,可以使用taskLock()taskUnLock()來解決;

  (3)有些CPU中斷是分級,我們可以用intLockLevelSet()intLockLevelGet()來操作中斷閉鎖的級別。缺省情況下,taskLock禁止所有等級的中斷。

  至此,我們可以對互斥問題進行一個系統的總結,主要有如下幾種方法:

  (1intLock禁止中斷:解決任務和ISR之間的互斥問題;

 int lock = intLock();
 //. . critical region that cannot be interrupted
 intUnlock(lock);

  (2taskLock禁止優先級搶占調度:當當前任務正在運行時,除了中斷服務程序外,高優先級的任務也不允許搶占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);

  總的來說,在實時系統中采取禁止中斷的方法會影響系統對外部中斷及時響應和處理的能力;而禁止優先級搶占調度方法阻止了高優先級的任務搶先運行,在實時系統中也是不適合的。因此,信號量無疑是解決互斥問題的最好方法。

總結

以上是生活随笔為你收集整理的基于嵌入式操作系统VxWorks的多任务并发程序设计――中断与任务的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。