内核在处理中断请求时,要求在单位时间内可以处理尽可能多的中断,也就是系统要求处理中断的吞吐率要尽可能地大。这就要求中断处理程序要尽可能地短小精悍,并且不能有耗时操作。但是大多数的中断处理程序是很复杂的,很难在短时间内处理完毕。为了提高系统的响应能力和并发能力,需要解决平衡中断处理程序时间要求短和工作量要大的问题,SylixOS 将中断处理分为两个阶段,也就是顶半部和底半部:
如果中断处理程序足够简单,则不需要分为顶半部和底半部,直接在顶半部完成即可。SylixOS 实现底半部的机制是中断延迟工作队列(InterDefer)。
接口 | 说明 |
---|---|
API_InterDeferGet | 获得对应 CPU 的中断延迟队列 |
API_InterDeferContext | 是否在中断延迟队列任务上下文 |
API_InterDeferJobAdd | 向中断延迟处理队列加入任务 |
API_InterDeferJobDelete | 从中断延迟处理队列删除任务 |
中断延迟工作队列基于内核工作队列实现,同时创建优先级为0(最高优先级)的执行线程。对于多核处理器可以选择每个核有自己独立的工作队列,也可以和单核一样使用单一工作队列模式。
/*********************************************************************************************************
**
** 中国软件开源组织
**
** 嵌入式实时操作系统
**
** SylixOS(TM) LW : long wing
**
** Copyright All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文 件 名: InterDefer.c
**
** 创 建 人: Han.Hui (韩辉)
**
** 文件创建日期: 2016 年 05 月 09 日
**
** 描 述: 中断延迟队列处理.
*********************************************************************************************************/
#define __SYLIXOS_KERNEL
#include "../SylixOS/kernel/include/k_kernel.h"
/*********************************************************************************************************
裁剪配置
*********************************************************************************************************/
#if LW_CFG_ISR_DEFER_EN > 0
/*********************************************************************************************************
每一个 CPU 的 DEFER ISR QUEUE
*********************************************************************************************************/
#if (LW_CFG_SMP_EN > 0) && (LW_CFG_ISR_DEFER_PER_CPU > 0)
static LW_JOB_QUEUE _K_jobqIsrDefer[LW_CFG_MAX_PROCESSORS];
static LW_JOB_MSG _K_jobmsgIsrDefer[LW_CFG_MAX_PROCESSORS][LW_CFG_ISR_DEFER_SIZE];
#else
static LW_JOB_QUEUE _K_jobqIsrDefer[1];
static LW_JOB_MSG _K_jobmsgIsrDefer[LW_CFG_ISR_DEFER_SIZE];
#endif /* LW_CFG_SMP_EN > 0 */
/*********************************************************************************************************
** 函数名称: __interDeferTask
** 功能描述: 获得中断堆栈使用量
** 输 入 : ulCPUId CPU 号
** pstFreeByteSize 空闲堆栈大小 (可为 LW_NULL)
** pstUsedByteSize 使用堆栈大小 (可为 LW_NULL)
** 输 出 :
** 全局变量:
** 调用模块:
*********************************************************************************************************/
static PVOID _interDeferTask (PVOID pvArg)
{
PLW_JOB_QUEUE pjobq = (PLW_JOB_QUEUE)pvArg;
for (;;) {
_jobQueueExec(pjobq, LW_OPTION_WAIT_INFINITE);
}
return (LW_NULL);
}
/*********************************************************************************************************
** 函数名称: _interDeferInit
** 功能描述: 初始化中断延迟处理
** 输 入 : NONE
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID _interDeferInit (VOID)
{
CHAR cDefer[LW_CFG_OBJECT_NAME_SIZE] = "t_isrdefer";
LW_CLASS_THREADATTR threadattr;
LW_OBJECT_HANDLE ulId;
#if (LW_CFG_SMP_EN > 0) && (LW_CFG_ISR_DEFER_PER_CPU > 0)
INT i;
LW_CLASS_CPUSET cpuset;
LW_CPU_ZERO(&cpuset);
API_ThreadAttrBuild(&threadattr,
LW_CFG_THREAD_DEFER_STK_SIZE,
LW_CFG_ISR_DEFER_PRIO,
(LW_OPTION_THREAD_STK_CHK |
LW_OPTION_THREAD_SAFE |
LW_OPTION_OBJECT_GLOBAL |
LW_OPTION_THREAD_DETACHED |
LW_OPTION_THREAD_AFFINITY_ALWAYS),
LW_NULL);
LW_CPU_FOREACH (i) {
if (_jobQueueInit(&_K_jobqIsrDefer[i],
&_K_jobmsgIsrDefer[i][0],
LW_CFG_ISR_DEFER_SIZE, LW_FALSE)) {
_DebugHandle(__ERRORMESSAGE_LEVEL, "can not create ISR defer queue.\r\n");
return;
}
lib_itoa(i, &cDefer[10], 10);
API_ThreadAttrSetArg(&threadattr, &_K_jobqIsrDefer[i]);
ulId = API_ThreadInit(cDefer, _interDeferTask, &threadattr, LW_NULL);
if (ulId == LW_OBJECT_HANDLE_INVALID) {
_DebugHandle(__ERRORMESSAGE_LEVEL, "can not create ISR defer task.\r\n");
return;
}
LW_CPU_SET(i, &cpuset);
API_ThreadSetAffinity(ulId, sizeof(LW_CLASS_CPUSET), &cpuset); /* 锁定到指定 CPU */
LW_CPU_CLR(i, &cpuset);
API_ThreadStart(ulId);
}
#else
if (_jobQueueInit(&_K_jobqIsrDefer[0],
&_K_jobmsgIsrDefer[0],
LW_CFG_ISR_DEFER_SIZE, LW_FALSE)) {
_DebugHandle(__ERRORMESSAGE_LEVEL, "can not create ISR defer queue.\r\n");
return;
}
API_ThreadAttrBuild(&threadattr,
LW_CFG_THREAD_DEFER_STK_SIZE,
LW_CFG_ISR_DEFER_PRIO,
(LW_OPTION_THREAD_STK_CHK |
LW_OPTION_THREAD_SAFE |
LW_OPTION_OBJECT_GLOBAL |
LW_OPTION_THREAD_DETACHED |
LW_OPTION_THREAD_AFFINITY_ALWAYS),
&_K_jobqIsrDefer[0]);
ulId = API_ThreadInit(cDefer, _interDeferTask, &threadattr, LW_NULL);
if (ulId == LW_OBJECT_HANDLE_INVALID) {
_DebugHandle(__ERRORMESSAGE_LEVEL, "can not create ISR defer task.\r\n");
return;
}
API_ThreadStart(ulId);
#endif /* LW_CFG_SMP_EN > 0 */
} /* LW_CFG_ISR_DEFER_PER_CPU */
/*********************************************************************************************************
** 函数名称: API_InterDeferGet
** 功能描述: 获得对应 CPU 的中断延迟队列
** 输 入 : ulCPUId CPU 号
** 输 出 : 中断延迟队列
** 全局变量:
** 调用模块:
API 函数
*********************************************************************************************************/
LW_API
PLW_JOB_QUEUE API_InterDeferGet (ULONG ulCPUId)
{
if (ulCPUId >= LW_NCPUS) {
_ErrorHandle(ERANGE);
return (LW_NULL);
}
#if (LW_CFG_SMP_EN > 0) && (LW_CFG_ISR_DEFER_PER_CPU > 0)
return (&_K_jobqIsrDefer[ulCPUId]);
#else
return (&_K_jobqIsrDefer[0]);
#endif /* LW_CFG_SMP_EN > 0 */
} /* LW_CFG_ISR_DEFER_PER_CPU */
/*********************************************************************************************************
** 函数名称: API_InterDeferJobAdd
** 功能描述: 向中断延迟处理队列加入一个任务
** 输 入 : pjobq 队列
** pfunc 处理函数
** pvArg 处理参数
** 输 出 : ERROR CODE
** 全局变量:
** 调用模块:
API 函数
*********************************************************************************************************/
LW_API
ULONG API_InterDeferJobAdd (PLW_JOB_QUEUE pjobq, VOIDFUNCPTR pfunc, PVOID pvArg)
{
if (!pjobq) {
_ErrorHandle(EINVAL);
return (EINVAL);
}
return (_jobQueueAdd(pjobq, pfunc, pvArg, LW_NULL, LW_NULL, LW_NULL, LW_NULL, LW_NULL));
}
/*********************************************************************************************************
** 函数名称: API_InterDeferJobDelete
** 功能描述: 从中断延迟处理队列删除任务
** 输 入 : pjobq 队列
** bMatchArg 是否进行参数匹配判断
** pfunc 处理函数
** pvArg 处理参数
** 输 出 : NONE
** 全局变量:
** 调用模块:
API 函数
*********************************************************************************************************/
LW_API
ULONG API_InterDeferJobDelete (PLW_JOB_QUEUE pjobq, BOOL bMatchArg, VOIDFUNCPTR pfunc, PVOID pvArg)
{
if (!pjobq) {
_ErrorHandle(EINVAL);
return (EINVAL);
}
_jobQueueDel(pjobq, (bMatchArg) ? 1 : 0,
pfunc, pvArg, LW_NULL, LW_NULL, LW_NULL, LW_NULL, LW_NULL);
return (ERROR_NONE);
}
#endif /* LW_CFG_ISR_DEFER_EN > 0 */
/*********************************************************************************************************
END
*********************************************************************************************************/
下列代码展示了 SylixOS 中断底半部在驱动开发中的使用,内核模块设置某个 GPIO 的中断处理函数并使能中断,当产生对应的按键中断时,中断处理函数会清除中断,并将耗时操作插入到中断延迟队列中,卸载内核模块时清除该 GPIO 的相关设置并删除工作队列。
#define __SYLIXOS_STDIO
#define __SYLIXOS_KERNEL
#include <SylixOS.h>
#include <module.h>
#define KEY_NUM 36
PVOID _G_pvWorkQueue;
static INT _G_iIrqNum;
static VOID __workHandler(PVOID pvArg)
{
printk("work handler function start.\n");
API_TimeSSleep(5);
printk("work handler function stop.\n");
}
static irqreturn_t GpioIsr (INT iGpioNum, ULONG ulVector)
{
API_GpioClearIrq(iGpioNum);
API_InterDeferJobAdd(API_InterDeferGet(0), __workHandler, NULL);
return (LW_IRQ_HANDLED);
}
void module_init (void)
{
INT iError;
iError = API_GpioRequestOne(KEY_NUM, LW_GPIOF_IN, "KEY");
if (iError != ERROR_NONE) {
printk("failed to request gpio %d!\n", KEY_NUM);
return;
}
_G_iIrqNum = API_GpioSetupIrq(KEY_NUM, LW_FALSE, 0);
if (_G_iIrqNum == PX_ERROR) {
printk("failed to setup gpio %d irq!\n", KEY_NUM);
return;
}
iError = API_InterVectorConnect((ULONG)_G_iIrqNum,
(PINT_SVR_ROUTINE)GpioIsr,
(PVOID)KEY_NUM,
"GpioIsr");
if (iError != ERROR_NONE) {
printk("failed to connect GpioIsr!\n");
return;
}
API_InterVectorEnable(_G_iIrqNum);
printk("interrupt_module init!\n");
}
void module_exit (void)
{
API_InterVectorDisconnect((ULONG)_G_iIrqNum,
(PINT_SVR_ROUTINE)GpioIsr,
(PVOID)KEY_NUM);
API_GpioFree(KEY_NUM);
printk("interrupt_module exit!\n");
}
在 SylixOS Shell 下装载模块,然后通过按下指定的按键触发中断:
#insmod ./interrupt.ko
interrupt_module init!
module interrupt.ko register ok, handle: 0x13338f0
work handler function start.
work handler function stop.
在 SylixOS Shell 下卸载模块:
#rmmod interrupt.ko
interrupt_module exit!
module /lib/modules/interrupt.ko unregister ok.