当前位置: 首页 > 工具软件 > SylixOS > 使用案例 >

SylixOS中断延迟队列

唐彬炳
2023-12-01

概念

内核在处理中断请求时,要求在单位时间内可以处理尽可能多的中断,也就是系统要求处理中断的吞吐率要尽可能地大。这就要求中断处理程序要尽可能地短小精悍,并且不能有耗时操作。但是大多数的中断处理程序是很复杂的,很难在短时间内处理完毕。为了提高系统的响应能力和并发能力,需要解决平衡中断处理程序时间要求短和工作量要大的问题,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.
 类似资料: