鸿蒙轻内核M核源码分析系列十 软件定时器Swtmr

软件定时器(Software Timer)是基于系统Tick时钟中断且由软件来模拟的定时器。当经过设定的Tick数后,会触发用户自定义的回调函数。硬件定时器受硬件的限制,数量上不足以满足用户的实际需求。鸿蒙轻内核提供了软件定时器功能可以提供更多的定时器,满足用户需求。

本文通过分析鸿蒙轻内核定时器模块的源码,掌握定时器使用上的差异。本文中所涉及的源码,以OpenHarmony LiteOS-M内核为例,均可以在开源站点 https://gitee.com/openharmony/kernel_liteos_m 获取。


接下来,我们看下定时器的结构体,定时器初始化,定时器常用操作的源代码。

1、定时器结构体定义和常用宏定义

1.1 定时器结构体定义

在文件kernel\include\los_swtmr.h定义的定时器控制块结构体为SWTMR_CTRL_S,结构体源代码如下。定时器状态.ucState取值OS_SWTMR_STATUS_UNUSEDOS_SWTMR_STATUS_CREATEDOS_SWTMR_STATUS_TICKING,定时器模式.mode取值LOS_SWTMR_MODE_ONCELOS_SWTMR_MODE_PERIODLOS_SWTMR_MODE_NO_SELFDELETE。其他结构体成员的解释见注释部分。

typedef struct tagSwTmrCtrl {
    struct tagSwTmrCtrl *pstNext;       /* 指向下一个定时器结构体的指针       */
    UINT8               ucState;        /* 定时器状态,取值枚举SwtmrState    */
    UINT8               ucMode;         /* 定时器模式,取值枚举enSwTmrType   */
#if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1)
    UINT8               ucRouses;       /* 唤醒开关                         */
    UINT8               ucSensitive;    /* 对齐开关                         */
#endif
    UINT32              usTimerID;      /* 定时器编号Id                     */
    UINT32              uwCount;        /* 定时器运行的次数                  */
    UINT32              uwInterval;     /* 周期定时器超时间隔 (单位: tick)   */
    UINT32              uwArg;          /* 定时器超时回调函数参数            */
    SWTMR_PROC_FUNC     pfnHandler;     /* 定时器超时回调函数                */
    SortLinkList        stSortList;     /* 定时器排序链表                    */
} SWTMR_CTRL_S;

另外,还对回调函数及其参数单独定义了一个结构体SwtmrHandlerItem,如下:

typedef struct {
    SWTMR_PROC_FUNC handler;    /**< 定时器超时回调函数    */
    UINTPTR arg;                /**< 定时器超时回调函数参数 */
} SwtmrHandlerItem;

1.2 定时器常用宏定义

定时器头文件kernel\include\los_swtmr.h中还提供了相关的枚举和宏,从定时器池里获取定时器控制块的宏定义OS_SWT_FROM_SID如下:

#define OS_SWT_FROM_SID(swtmrId)    ((SWTMR_CTRL_S *)g_swtmrCBArray + ((swtmrId) % LOSCFG_BASE_CORE_SWTMR_LIMIT))

头文件中定义的定时器几个枚举如下:

enum SwtmrState {
    OS_SWTMR_STATUS_UNUSED,     /**< 定时器未使用    */
    OS_SWTMR_STATUS_CREATED,    /**< 定时器已创建     */
    OS_SWTMR_STATUS_TICKING     /**< 定时器计时中     */
};

#if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1)

enum enSwTmrRousesType {
    OS_SWTMR_ROUSES_IGNORE, /* 定时器不能唤醒系统 */
    OS_SWTMR_ROUSES_ALLOW,  /* 定时器能唤醒系统 */
};

enum enSwTmrAlignSensitive {
    OS_SWTMR_ALIGN_SENSITIVE,   /* 定时器不需要对齐 */
    OS_SWTMR_ALIGN_INSENSITIVE, /* 定时器需要对齐 */
};
#endif

enum EnSwTmrType {
    LOS_SWTMR_MODE_ONCE,            /* 一次性定时器, 值为0\. */
    LOS_SWTMR_MODE_PERIOD,          /* 周期定时器,值为 1\. */
    LOS_SWTMR_MODE_NO_SELFDELETE,   /* 一次性定时器,不会自删除,值为2 */
    LOS_SWTMR_MODE_OPP,             /* 一次性定时器完成后,使能周期性定时器。该模式暂不支持。值为3 */
};

2、定时器初始化

定时器在内核中默认开启,用户可以通过宏LOSCFG_BASE_CORE_SWTMR进行关闭。开启定时器的情况下,在系统启动时,在kernel\src\los_init.c中调用OsSwtmrInit()进行定时器模块初始化。下面,我们分析下定时器初始化的代码。

⑴处如果开启定时器对齐宏LOSCFG_BASE_CORE_SWTMR_ALIGN,清零g_swtmrAlignID数组。定时器的数量由宏LOSCFG_BASE_CORE_SWTMR_LIMIT定义,⑵处计算定时器池需要的内存大小,然后为定时器申请内存,如果申请失败,则返回错误。⑶初始化空闲定时器链表g_swtmrFreeList,维护未使用的定时器。循环每一个定时器进行初始化,为每一个定时器节点指定索引timerId,定时器控制块依次指向下一个定时器控制块。

⑷处代码为定时器创建队列,队列的消息大小OS_SWTMR_HANDLE_QUEUE_SIZE等于定时器的数量LOSCFG_BASE_CORE_SWTMR_LIMIT,消息内容的最大大小sizeof(SwtmrHandlerItem)。后文分析定时器队列读取写入消息的时候具体来看是什么消息。⑸处调用函数OsSwtmrTaskCreate()创建定时器任务,定时器任务优先级最高,任务的入口函数为OsSwtmrTask(),后文会分析该函数。⑹处初始化定时器排序链表,源码分析系列之前的文章分析过,可以阅读下排序链表数据结构章节。⑺处注册定时器扫描函数OsSwtmrScan

LITE_OS_SEC_TEXT_INIT UINT32 OsSwtmrInit(VOID)
{
    UINT32 size;
    UINT16 index;
    UINT32 ret;

#if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1)
    // Ignore the return code when matching CSEC rule 6.6(1).
⑴  (VOID)memset_s((VOID *)g_swtmrAlignID, sizeof(SwtmrAlignData) * LOSCFG_BASE_CORE_SWTMR_LIMIT,
                   0, sizeof(SwtmrAlignData) * LOSCFG_BASE_CORE
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值