基于TI-RTOS的CC2650DK开发(13)---门

judy的头像

Gates(门)

Gates是用于防止并发访问代码关键区域的设备。各种门关于如何锁住关键区域的实现并不一样。

线程可以被更高优先级线程抢占,一些代码段在被另一个线程执行前需要被一个线程执行完毕。使用代码改变关键区域的全局变量这样的普通应用需要通过Gate来进行保护。

Gates通常用于禁用一些级别的抢占,如禁用task切换或甚至硬件中断,或用于二元semaphore。通过使用一个key,所有Gate实现支持嵌套。

对于禁止函数抢占的门来说,有可能多个线程调用Gate_enter(),但在所有线程调用Gate_leave()之后,才能重新载入抢占。这个功能通过使用一个key来实现。调用Gate_enter()时返回的key必须在之后传递回Gate_leave()。只有最外层调用的Gate_enter()返回正确的key才会重新载入抢占。

如以下例子所示,在实现中函数名称用的是实际模块名称而不是“Gate”。
运行时实例:以下C代码通过Gate保护关键区域。此例使用了GateHwi来实现中断机构的启用、禁用。
UInt gateKey;
GateHwi_Handle gateHwi;
GateHwi_Params prms;
Error_Block eb;
Error_init(&eb);
GateHwi_Params_init(&prms);
gateHwi = GateHwi_create(&prms, &eb);
if (gateHwi == NULL)
{
System_abort("Gate create failed");
}
/* Simultaneous operations on a global variable by multiple
* threads could cause problems, so modifications to the global
* variable are protected with a Gate. */
gateKey = GateHwi_enter(gateHwi);
myGlobalVar = 7;
GateHwi_leave(gateHwi, gateKey);

基于抢占的Gate实现

以下gates实现使用了某些形式的抢占禁用:
ti.sysbios.gates.GateHwi
ti.sysbios.gates.GateSwi
ti.sysbios.gates.GateTask

GateHwi

GateHwi是启用和禁用中断的锁定机构。这种门保证了CPU的独占访问。此门可用于关键区域由Task、Swi或Hwi线程共享时。从进入到离开所需时间应尽可能短于最小Hwi延迟。

GateSwi

GateSwi是启用和禁用软件中断的锁定机构。此门可用于关键区域由Task、Swi线程共享时。此门不能用于Hwi线程。从进入到离开所需时间应尽可能短于最小Swi延迟。

GateTask

GateSwi是启用和禁用task的锁定机构。此门在关键区域由Task线程共享时使用。此门不能被Hwi和Swi线程使用。从进入到离开所需时间应尽可能短于最小Task延迟。

基于信号量的Gate实现

以下门实现使用了信息量:
ti.sysbios.gates.GateMutex
ti.sysbios.gates.GateMutexPri

GateMutex

GateMutex使用了一个二元信号量作为锁定机构。每个GateMutex实例都有其自己唯一的信号量。因为此门有可能阻塞,它不能用于Swi或Hwi线程,只能被Task线程使用。

GateMutexPri

GateMutexPri是一种互斥Gate(同一时间只能被一个线程操作)。它实现了“优先权继承性”以防止优先反转。优先反转发生于高优先级Task在等待低优先级Task的Gate控制而导致的事实上的“反转”。
优先反转的问题和解决方案在4.3.3节描述。

配置实例:下例指定了一个用于HeapMem的GateType(见7.8.2节的HeapMem了解进一步描述)
var GateMutexPri = xdc.useModule('ti.sysbios.gates.GateMutexPri');
var HeapMem = xdc.useModule('ti.sysbios.heaps.HeapMem');
HeapMem.common$.gate = GateMutexPri.create();

优先反转

下例演示了优先反转问题。一个系统有三个低、中、高优先级task---每个task的优先级依照它的名字。低task最先运行并获得gate。高task准备运行抢占低task,试图获得gate并等待。接下来中task准备运行并抢占低task。现在高task必须等待中低task都完成后才能开始运行。这种情况下,低task事实上拥有更高的优先级。

解决方案:优先继承

要避免优先反转,可使用GateMutexPri实现优先继承。当高task试图获取低task的gate,低task的优先级应在高task等待期间暂时升为高优先级。这样高task将它的优先级捐献给低task。这样,当多个task等待gate,gate拥有者将收到所有等待者中的最高优先级。

附加说明

优先继承无法完全避免优先反转。Tasks仅在调用进入一个gate时捐献它们的优先级,所以如果一个task在等待gate期间,优先级获得提升,这种优先级无法贯穿整个gate所有者。

这种情况会在涉及多个门的时候发生。例如,一个系统拥有四个task:很低、低、中和高,每个task的优先级和它的名字一样。很低task最先运行,并获得gate A。低task第二个运行并获得gate B,此时等待gate A。高task运行并等待gate B,高task捐献它的优先级给低task,但低task被很低task阻塞,此时尽管使用了gate,优先反转还是发生了。这个问题的解决方案是围绕它设计,如果gate A可能被一个高优先级,时间敏感task需要,就应该被设计为长时间内无task控制此门或控制此门时阻塞。

当多个tasks等待此gate,它们按照优先级顺序接收此gate(高优先级task先收到此门)。这是因为GateMutexPRi的等待tasks列表按优先级排序,而不是FIFO。

调用GateMutexPri_enter()可能被阻塞,所以此门只能用于task上下文。GateMutexPri为非确定性调用,因为它将等待列表按优先级进行排序。

配置SYS/BIOS门类型

应用程序通过调用TI RTS类库(第6章)来设置gate类型。gate类型的选择用于保证重入RTS APIS。配置属性BIOS.rtsGateType控制此行为。在XGCONF,此属性被标记为“C标准库锁”。

gate类型取决于将要被RTS库函数调用的线程类型。例如,假设Swi和Task线程都将要被RTS库的System_printf()函数调用,则需使用GateSwi。此时,在Swi或Task线程调用System_printf()期间,Hwi线程将不可用。

如果使用了NoLocking,将不会加入RTS锁,则无法保证重入TI RTS库调用。应用程序如果需要,可直接插入RTS锁。

可用的gate类型在4.3.1节和4.3.2节列出,注意,GateTask不支持作为SYS/BIOS RTS门类型。
GateHwi:中断不可用并恢复保持重入。在Hwi中调用任意RTS时使用。
GateSwi:Swis不可用并恢复保持重入。在Swis中调用任意RTS而不是在任何Hwis中调用时使用。
GateMutex:单个mutex用于保持重入。仅在Tasks中调用RTS时使用。阻塞唯一的且试图执行RTS库关键区域的Tasks。
GateMutexPri:优先继承互斥用于保持重入。阻塞唯一的且试图执行RTS库关键区域的Tasks。提升正在执行RTS库关键区域的task的优先权,让优先权等于所有被mutex阻塞的task中优先级最高的那个。

默认RTS门类型取决于其它配置参数中的线程模型类型。如果BIOS.taskEnabled为true,则可使用GateMutex。如果BIOS.swiEnabled为true且BIOS.taskEnabled为false,则使用GateSwi。如果BIOS.swiEnabled和 BIOS.taskEnabled都为false,则使用xdc.runtime.GateNull。

如果BIOS.taskEnabled为false,用户将不能选择GateMutex(或其它Task级别gates)。同样地,如果BIOS.taskEnabled和BIOS.swiEnabled为false,用户将不能选择GateSwi或Task级别gates。

转自: abatei的专栏