SylixOS中断抢占
SylixOS是支持中断抢占的,通过IRQ的FLAG标志LW_IRQ_FLAG_PREEMPTIVE进行控制。SylixOS可以通过两种方式设置中断抢占,第一种是Arch层通过archIntHandle实现的,第二种是通过API_InterVectorSetFlag进行控制。这两种方式最终实现效果都是在Arch层实现的。
Arch层实现
在Arch层archIntHandle负责处理具体中断,archIntHandle代码实现如下。通过参数bPreemptive可以看出,它控制着当前中断是否能够被抢占,如果为true则可以被抢占,通过这种方式设置,如果可可抢占则所有中断都支持抢占。
/*********************************************************************************************************
** 函数名称: archIntHandle
** 功能描述: bspIntHandle 需要调用此函数处理中断 (关闭中断情况被调用)
** 输 入 : ulVector 中断向量
** bPreemptive 中断是否可抢占
** 输 出 : NONE
** 全局变量:
** 调用模块:
** 注 意 : 此函数退出时必须为中断关闭状态.
*********************************************************************************************************/
LW_WEAK VOID archIntHandle (ULONG ulVector, BOOL bPreemptive)
{
REGISTER irqreturn_t irqret;
if (_Inter_Vector_Invalid(ulVector)) {
return; /* 向量号不正确 */
}
if (LW_IVEC_GET_FLAG(ulVector) & LW_IRQ_FLAG_PREEMPTIVE) {
bPreemptive = LW_TRUE;
}
if (bPreemptive) {
VECTOR_OP_LOCK();
__ARCH_INT_VECTOR_DISABLE(ulVector); /* 屏蔽 vector 中断 */
VECTOR_OP_UNLOCK();
KN_INT_ENABLE_FORCE(); /* 允许中断 */
}
irqret = API_InterVectorIsr(ulVector); /* 调用中断服务程序 */
KN_INT_DISABLE(); /* 禁能中断 */
if (bPreemptive) {
if (irqret != LW_IRQ_HANDLED_DISV) {
VECTOR_OP_LOCK();
__ARCH_INT_VECTOR_ENABLE(ulVector); /* 允许 vector 中断 */
VECTOR_OP_UNLOCK();
}
} else if (irqret == LW_IRQ_HANDLED_DISV) {
VECTOR_OP_LOCK();
__ARCH_INT_VECTOR_DISABLE(ulVector); /* 屏蔽 vector 中断 */
VECTOR_OP_UNLOCK();
}
}
API接口实现
从archIntHandle代码实现中可以看到,它会通过LW_IVEC_GET_FLAG检查此中断使用使能标志LW_IRQ_FLAG_PREEMPTIVE,如果使能则 bPreemptive 置位,同样实现此中断抢占。
if (LW_IVEC_GET_FLAG(ulVector) & LW_IRQ_FLAG_PREEMPTIVE) {
bPreemptive = LW_TRUE;
}
而LW_IVEC_GET_FLAG宏函数是通过获取对应中断向量标志IDESC_ulFlag实现控制中断抢占的。通过代码可以看出,每个中断向量都可以单独控制中断标志,也就是都可以单独控制中断抢占。
#define LW_IVEC_GET_FLAG(vector) \
(_K_idescTable[vector].IDESC_ulFlag)
API_InterVectorSetFlag具体代码实现如下,可以看出根据中断向量号,分别设置中断标志。
/*********************************************************************************************************
** 函数名称: API_InterVectorSetFlag
** 功能描述: 设置指定中断向量的特性.
** 输 入 : ulVector 中断向量号
** ulFlag 特性
** 输 出 : ERROR CODE
** 全局变量:
** 调用模块:
** 注 意 : LW_IRQ_FLAG_QUEUE 必须在安装任何一个驱动前设置, 且设置后不再能取消.
最好放在 bspIntInit() 函数中完成设置.
API 函数
*********************************************************************************************************/
LW_API
ULONG API_InterVectorSetFlag (ULONG ulVector, ULONG ulFlag)
{
INTREG iregInterLevel;
PLW_CLASS_INTDESC pidesc;
if (_Inter_Vector_Invalid(ulVector)) {
_ErrorHandle(ERROR_KERNEL_VECTOR_NULL);
return (ERROR_KERNEL_VECTOR_NULL);
}
pidesc = LW_IVEC_GET_IDESC(ulVector);
LW_SPIN_LOCK_QUICK(&pidesc->IDESC_slLock, &iregInterLevel); /* 关闭中断同时锁住 spinlock */
if (LW_IVEC_GET_FLAG(ulVector) & LW_IRQ_FLAG_QUEUE) { /* 已经是 QUEUE 类型中断向量 */
LW_IVEC_SET_FLAG(ulVector, ulFlag | LW_IRQ_FLAG_QUEUE);
} else {
LW_IVEC_SET_FLAG(ulVector, ulFlag);
}
LW_SPIN_UNLOCK_QUICK(&pidesc->IDESC_slLock, iregInterLevel); /* 打开中断, 同时打开 spinlock */
return (ERROR_NONE);
}
总结
API_InterVectorSetFlag可以指定某个中断可以被抢占,就是当这个中断发生时,其他中断可以抢占。而archIntHandle是在bsp适配时指定全部中断都可抢占,是通过ARCH中的archIntHandle参数实现的。