摘要:本文经过分析鸿蒙轻内核定时器模块的源码,掌握定时器使用上的差别。
本文分享自华为云社区《鸿蒙轻内核M核源码分析系列十四 软件定时器Swtmr》,做者:zhushy 。git
软件定时器(Software Timer)是基于系统Tick时钟中断且由软件来模拟的定时器。当通过设定的Tick数后,会触发用户自定义的回调函数。硬件定时器受硬件的限制,数量上不足以知足用户的实际需求。鸿蒙轻内核提供了软件定时器功能能够提供更多的定时器,知足用户需求。数组
本文经过分析鸿蒙轻内核定时器模块的源码,掌握定时器使用上的差别。本文中所涉及的源码,以OpenHarmony LiteOS-M内核为例,都可以在开源站点https://gitee.com/openharmony/kernel_liteos_m 获取。数据结构
接下来,咱们看下定时器的结构体,定时器初始化,定时器经常使用操做的源代码。函数
在文件kernel\include\los_swtmr.h定义的定时器控制块结构体为SWTMR_CTRL_S,结构体源代码以下。定时器状态.ucState取值OS_SWTMR_STATUS_UNUSED、OS_SWTMR_STATUS_CREATED或OS_SWTMR_STATUS_TICKING,定时器模式.mode取值LOS_SWTMR_MODE_ONCE、LOS_SWTMR_MODE_PERIOD或LOS_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,以下:spa
typedef struct { SWTMR_PROC_FUNC handler; /**< 定时器超时回调函数 */ UINTPTR arg; /**< 定时器超时回调函数参数 */ } SwtmrHandlerItem;
定时器头文件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 */ };
定时器在内核中默认开启,用户能够经过宏LOSCFG_BASE_CORE_SWTMR进行关闭。开启定时器的状况下,在系统启动时,在kernel\src\los_init.c中调用OsSwtmrInit()进行定时器模块初始化。下面,咱们分析下定时器初始化的代码。code
⑴处若是开启定时器对齐宏LOSCFG_BASE_CORE_SWTMR_ALIGN,清零g_swtmrAlignID数组。定时器的数量由宏LOSCFG_BASE_CORE_SWTMR_LIMIT定义,⑵处计算定时器池须要的内存大小,而后为定时器申请内存,若是申请失败,则返回错误。⑶初始化空闲定时器链表g_swtmrFreeList,维护未使用的定时器。循环每个定时器进行初始化,为每个定时器节点指定索引timerId,定时器控制块依次指向下一个定时器控制块。blog
⑷处代码为定时器建立队列,队列的消息大小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_SWTMR_LIMIT); #endif ⑵ size = sizeof(SWTMR_CTRL_S) * LOSCFG_BASE_CORE_SWTMR_LIMIT; SWTMR_CTRL_S *swtmr = (SWTMR_CTRL_S *)LOS_MemAlloc(m_aucSysMem0, size); if (swtmr == NULL) { return LOS_ERRNO_SWTMR_NO_MEMORY; } // Ignore the return code when matching CSEC rule 6.6(3). (VOID)memset_s((VOID *)swtmr, size, 0, size); g_swtmrCBArray = swtmr; ⑶ g_swtmrFreeList = swtmr; swtmr->usTimerID = 0; SWTMR_CTRL_S *temp = swtmr; swtmr++; for (index = 1; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++, swtmr++) { swtmr->usTimerID = index; temp->pstNext = swtmr; temp = swtmr; } ⑷ ret = LOS_QueueCreate((CHAR *)NULL, OS_SWTMR_HANDLE_QUEUE_SIZE, &g_swtmrHandlerQueue, 0, sizeof(SwtmrHandlerItem)); if (ret != LOS_OK) { (VOID)LOS_MemFree(m_aucSysMem0, swtmr); return LOS_ERRNO_SWTMR_QUEUE_CREATE_FAILED; } ⑸ ret = OsSwtmrTaskCreate(); if (ret != LOS_OK) { (VOID)LOS_MemFree(m_aucSysMem0, swtmr); return LOS_ERRNO_SWTMR_TASK_CREATE_FAILED; } ⑹ g_swtmrSortLinkList = OsGetSortLinkAttribute(OS_SORT_LINK_SWTMR); if (g_swtmrSortLinkList == NULL) { (VOID)LOS_MemFree(m_aucSysMem0, swtmr); return LOS_NOK; } ret = OsSortLinkInit(g_swtmrSortLinkList); if (ret != LOS_OK) { (VOID)LOS_MemFree(m_aucSysMem0, swtmr); return LOS_NOK; } ⑺ ret = OsSchedSwtmrScanRegister((SchedScan)OsSwtmrScan); if (ret != LOS_OK) { (VOID)LOS_MemFree(m_aucSysMem0, swtmr); return LOS_NOK; } return LOS_OK; }
咱们再看一下定时器任务的入口函数为OsSwtmrTask()。⑴进行for永久循环,队列读取不到数据时会阻塞,由于优先级比较高,定时器队列有数据时该任务就会执行。从定时器队列中读取定时器处理函数地址放入指针地址&swtmrHandle,读取的长度为sizeof(SwtmrHandlerItem)。成功读取后,获取定时器回调函数及其参数,而后⑵处执行定时器回调函数。记录定时器回调函数的执行时间,⑶处判断执行时间是否超时,若是超时,打印警告信息。
LITE_OS_SEC_TEXT VOID OsSwtmrTask(VOID) { SwtmrHandlerItem swtmrHandle; UINT32 readSize; UINT32 ret; UINT64 tick; readSize = sizeof(SwtmrHandlerItem); for (;;) { ⑴ ret = LOS_QueueReadCopy(g_swtmrHandlerQueue, &swtmrHandle, &readSize, LOS_WAIT_FOREVER); if ((ret == LOS_OK) && (readSize == sizeof(SwtmrHandlerItem))) { if (swtmrHandle.handler == NULL) { continue; } tick = LOS_TickCountGet(); ⑵ swtmrHandle.handler(swtmrHandle.arg); tick = LOS_TickCountGet() - tick; ⑶ if (tick >= SWTMR_MAX_RUNNING_TICKS) { PRINT_WARN("timer_handler(%p) cost too many ms(%d)\n", swtmrHandle.handler, (UINT32)((tick * OS_SYS_MS_PER_SECOND) / LOSCFG_BASE_CORE_TICK_PER_SECOND)); } } } }
咱们分析下建立定时器函数LOS_SwtmrCreate()的代码。先不考虑定时器对齐LOSCFG_BASE_CORE_SWTMR_ALIGN的状况。先看下函数参数,interval是定时器执行时间间隔,mode是建立的定时器模式,handler、arg是定时器回调函数及其参数。swtmrId是定时器编号。
⑴处对传入参数定时器超时间隔、定时器模式、回调函数,定时器编号进行校验。⑵判断空闲定时器池是否为空,为空则返回错误,没法建立定时器。⑶处若是定时器不为空,则获取定时器控制块swtmr。⑷处对定时器控制块信息进行初始化。⑸处把该定时器排序链表节点的响应时间responseTime初始化为-1。
#if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1) LITE_OS_SEC_TEXT_INIT UINT32 LOS_SwtmrCreate(UINT32 interval, UINT8 mode, SWTMR_PROC_FUNC handler, UINT32 *swtmrId, UINT32 arg, UINT8 rouses, UINT8 sensitive) #else LITE_OS_SEC_TEXT_INIT UINT32 LOS_SwtmrCreate(UINT32 interval, UINT8 mode, SWTMR_PROC_FUNC handler, UINT32 *swtmrId, UINT32 arg) #endif { SWTMR_CTRL_S *swtmr = NULL; UINT32 intSave; ⑴ if (interval == 0) { return LOS_ERRNO_SWTMR_INTERVAL_NOT_SUITED; } if ((mode != LOS_SWTMR_MODE_ONCE) && (mode != LOS_SWTMR_MODE_PERIOD) && (mode != LOS_SWTMR_MODE_NO_SELFDELETE)) { return LOS_ERRNO_SWTMR_MODE_INVALID; } if (handler == NULL) { return LOS_ERRNO_SWTMR_PTR_NULL; } if (swtmrId == NULL) { return LOS_ERRNO_SWTMR_RET_PTR_NULL; } #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1) if ((rouses != OS_SWTMR_ROUSES_IGNORE) && (rouses != OS_SWTMR_ROUSES_ALLOW)) { return OS_ERRNO_SWTMR_ROUSES_INVALID; } if ((sensitive != OS_SWTMR_ALIGN_INSENSITIVE) && (sensitive != OS_SWTMR_ALIGN_SENSITIVE)) { return OS_ERRNO_SWTMR_ALIGN_INVALID; } #endif intSave = LOS_IntLock(); ⑵ if (g_swtmrFreeList == NULL) { LOS_IntRestore(intSave); return LOS_ERRNO_SWTMR_MAXSIZE; } ⑶ swtmr = g_swtmrFreeList; g_swtmrFreeList = swtmr->pstNext; LOS_IntRestore(intSave); ⑷ swtmr->pfnHandler = handler; swtmr->ucMode = mode; swtmr->uwInterval = interval; swtmr->pstNext = (SWTMR_CTRL_S *)NULL; swtmr->uwCount = 0; swtmr->uwArg = arg; #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1) swtmr->ucRouses = rouses; swtmr->ucSensitive = sensitive; #endif swtmr->ucState = OS_SWTMR_STATUS_CREATED; *swtmrId = swtmr->usTimerID; ⑸ SET_SORTLIST_VALUE(&swtmr->stSortList, OS_SORT_LINK_INVALID_TIME); return LOS_OK; }
咱们可使用函数LOS_SwtmrDelete(UINT32 swtmrId)来删除定时器,下面经过分析源码看看如何删除定时器的。
⑴处判判定时器swtmrId是否超过OS_SWTMR_MAX_TIMERID,若是超过则返回错误码。若是定时器编号没有问题,获取定时器控制块LosSwtmrCB *swtmr。⑵处判断要删除的定时器swtmrId是否匹配,不匹配则返回错误码。⑶处判判定时器的状态,若是定时器定时器没有建立,不能删除。若是定时器计时中,须要先中止OsSwtmrStop(swtmr),而后再删除OsSwtmrDelete(swtmr)。
LITE_OS_SEC_TEXT UINT32 LOS_SwtmrDelete(UINT32 swtmrId) { SWTMR_CTRL_S *swtmr = NULL; UINT32 intSave; UINT32 ret = LOS_OK; UINT16 swtmrCbId; ⑴ if (swtmrId >= OS_SWTMR_MAX_TIMERID) { return LOS_ERRNO_SWTMR_ID_INVALID; } intSave = LOS_IntLock(); swtmrCbId = swtmrId % LOSCFG_BASE_CORE_SWTMR_LIMIT; swtmr = g_swtmrCBArray + swtmrCbId; ⑵ if (swtmr->usTimerID != swtmrId) { LOS_IntRestore(intSave); return LOS_ERRNO_SWTMR_ID_INVALID; } ⑶ switch (swtmr->ucState) { case OS_SWTMR_STATUS_UNUSED: ret = LOS_ERRNO_SWTMR_NOT_CREATED; break; case OS_SWTMR_STATUS_TICKING: OsSwtmrStop(swtmr); /* fall through */ case OS_SWTMR_STATUS_CREATED: OsSwtmrDelete(swtmr); break; default: ret = LOS_ERRNO_SWTMR_STATUS_INVALID; break; } LOS_IntRestore(intSave); return ret; }
接下来,咱们继续看看如何调用函数OsSwtmrDelete(swtmr)删除定时器。函数特别简单,把定时器放入空闲定时器链表g_swtmrFreeList头部,而后把定时器状态改成未使用状态就完成了删除。
STATIC_INLINE VOID OsSwtmrDelete(SWTMR_CTRL_S *swtmr) { /* insert to free list */ swtmr->pstNext = g_swtmrFreeList; g_swtmrFreeList = swtmr; swtmr->ucState = OS_SWTMR_STATUS_UNUSED; #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1) (VOID)memset_s((VOID *)&g_swtmrAlignID[swtmr->usTimerID % LOSCFG_BASE_CORE_SWTMR_LIMIT], sizeof(SwtmrAlignData), 0, sizeof(SwtmrAlignData)); #endif }
建立完毕定时器后,咱们可使用函数LOS_SwtmrStart(UINT32 swtmrId)来启动定时器,下面经过分析源码看看如何启动定时器的。
⑴处判判定时器swtmrId是否超过OS_SWTMR_MAX_TIMERID,若是超过则返回错误码。若是定时器编号没有问题,获取定时器控制块LosSwtmrCB *swtmr。⑵处判断要启动的定时器swtmrId是否匹配,不匹配则返回错误码。⑶处判判定时器的状态,若是定时器定时器没有建立,不能启动。若是定时器计时中,须要先中止OsSwtmrStop(swtmr),而后再启动OsSwtmrStart(swtmr)。
LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStart(UINT32 swtmrId) { UINT32 intSave; UINT32 ret = LOS_OK; ⑴ if (swtmrId >= OS_SWTMR_MAX_TIMERID) { return LOS_ERRNO_SWTMR_ID_INVALID; } intSave = LOS_IntLock(); SWTMR_CTRL_S *swtmr = g_swtmrCBArray + swtmrId % LOSCFG_BASE_CORE_SWTMR_LIMIT; ⑵ if (swtmr->usTimerID != swtmrId) { LOS_IntRestore(intSave); return LOS_ERRNO_SWTMR_ID_INVALID; } #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1) if ((swtmr->ucSensitive == OS_SWTMR_ALIGN_INSENSITIVE) && (swtmr->ucMode == LOS_SWTMR_MODE_PERIOD)) { UINT32 swtmrAlignIdIndex = swtmr->usTimerID % LOSCFG_BASE_CORE_SWTMR_LIMIT; g_swtmrAlignID[swtmrAlignIdIndex].canAlign = 1; if ((swtmr->uwInterval % LOS_COMMON_DIVISOR) == 0) { g_swtmrAlignID[swtmrAlignIdIndex].canMultiple = 1; g_swtmrAlignID[swtmrAlignIdIndex].times = swtmr->uwInterval / LOS_COMMON_DIVISOR; } } #endif ⑶ switch (swtmr->ucState) { case OS_SWTMR_STATUS_UNUSED: ret = LOS_ERRNO_SWTMR_NOT_CREATED; break; case OS_SWTMR_STATUS_TICKING: OsSwtmrStop(swtmr); /* fall through */ case OS_SWTMR_STATUS_CREATED: OsSwtmrStart(swtmr); break; default: ret = LOS_ERRNO_SWTMR_STATUS_INVALID; break; } LOS_IntRestore(intSave); return ret; }
接下来,咱们继续看看如何调用函数OsSwtmrStart(swtmr)启动定时器。函数特别简单,⑴设置定时器的等待超时时间,并把定时器状态改成计时中。⑵处把该定时器插入超时排序链表中。若是已使能任务调度,则修改过时时间。
LITE_OS_SEC_TEXT VOID OsSwtmrStart(SWTMR_CTRL_S *swtmr) { UINT64 currTime = OsGetCurrSchedTimeCycle(); ⑴ swtmr->uwCount = swtmr->uwInterval; swtmr->ucState = OS_SWTMR_STATUS_TICKING; #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1) if ((g_swtmrAlignID[swtmr->usTimerID % LOSCFG_BASE_CORE_SWTMR_LIMIT].canAlign == 1) && (g_swtmrAlignID[swtmr->usTimerID % LOSCFG_BASE_CORE_SWTMR_LIMIT].isAligned == 0)) { g_swtmrAlignID[swtmr->usTimerID % LOSCFG_BASE_CORE_SWTMR_LIMIT].isAligned = 1; OsSwtmrFindAlignPos(currTime, swtmr); } #endif ⑵ OsAdd2SortLink(&swtmr->stSortList, currTime, swtmr->uwCount, OS_SORT_LINK_SWTMR); if (LOS_TaskIsRunning()) { ⑶ OsSchedUpdateExpireTime(currTime); } }
咱们可使用函数LOS_SwtmrStop(UINT32 swtmrId)来中止定时器,下面经过分析源码看看如何中止定时器的。
⑴处判判定时器swtmrId是否超过OS_SWTMR_MAX_TIMERID,若是超过则返回错误码。若是定时器编号没有问题,获取定时器控制块LosSwtmrCB *swtmr。⑵处判断要启动的定时器swtmrId是否匹配,不匹配则返回错误码。⑶处判判定时器的状态,若是定时器定时器没有建立,没有启动,不能中止。若是定时器计时中,会继续调用OsSwtmrStop(swtmr)中止定时器。
LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStop(UINT32 swtmrId) { SWTMR_CTRL_S *swtmr = NULL; UINT32 intSave; UINT16 swtmrCbId; UINT32 ret = LOS_OK; ⑴ if (swtmrId >= OS_SWTMR_MAX_TIMERID) { return LOS_ERRNO_SWTMR_ID_INVALID; } intSave = LOS_IntLock(); swtmrCbId = swtmrId % LOSCFG_BASE_CORE_SWTMR_LIMIT; swtmr = g_swtmrCBArray + swtmrCbId; ⑵ if (swtmr->usTimerID != swtmrId) { LOS_IntRestore(intSave); return LOS_ERRNO_SWTMR_ID_INVALID; } ⑶ switch (swtmr->ucState) { case OS_SWTMR_STATUS_UNUSED: ret = LOS_ERRNO_SWTMR_NOT_CREATED; break; case OS_SWTMR_STATUS_CREATED: ret = LOS_ERRNO_SWTMR_NOT_STARTED; break; case OS_SWTMR_STATUS_TICKING: OsSwtmrStop(swtmr); break; default: ret = LOS_ERRNO_SWTMR_STATUS_INVALID; break; } LOS_IntRestore(intSave); return ret; }
接下来,咱们继续看看如何调用函数OsSwtmrStop(swtmr)中止定时器。函数特别简单,⑴处从排序链表中删除该定时器的排序链表节点,更改定时器的状态。⑵若是已使能任务调度,则修改过时时间。
LITE_OS_SEC_TEXT VOID OsSwtmrStop(SWTMR_CTRL_S *swtmr) { ⑴ OsDeleteSortLink(&swtmr->stSortList, OS_SORT_LINK_SWTMR); swtmr->ucState = OS_SWTMR_STATUS_CREATED; if (LOS_TaskIsRunning()) { ⑵ OsSchedUpdateExpireTime(OsGetCurrSchedTimeCycle()); #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1) g_swtmrAlignID[swtmr->usTimerID % LOSCFG_BASE_CORE_SWTMR_LIMIT].isAligned = 0; #endif } }
定时器加入到超时排序链表后,随时时间一个tick一个tick的逝去,须要不断的检查定时器是否超时到期。从以前的文章,已经知道系统每走过一个tick,系统就会调用一次Tick中断的处理函数OsTickHandler(),该函数会调用定时器扫描函数OsSwtmrScan()来扫描、更新定时器时间。咱们看下OsSwtmrScan()的代码。
⑴处获取超时排序链表的链表节点listObject,⑵判断排序链表是否为空,为空则返回。⑶获取排序链表的下一个链表节点sortList。⑷循环遍历超时排序链表上响应时间小于等于当前时间的链表节点,意味着定时器到期,须要处理定时器的回调函数。⑸从超时排序链表中删除超时的节点,⑹获取定时器控制块SWTMR_CTRL_S *swtmr,调用函数OsSwtmrTimeoutHandle(swtmr)执行定时器回调函数,并设置须要调度的标记needSchedule。⑺若是超时排序链表为空则终止循环。
STATIC BOOL OsSwtmrScan(VOID) { BOOL needSchedule = FALSE; ⑴ LOS_DL_LIST *listObject = &g_swtmrSortLinkList->sortLink; ⑵ if (LOS_ListEmpty(listObject)) { return needSchedule; } ⑶ SortLinkList *sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode); UINT64 currTime = OsGetCurrSchedTimeCycle(); ⑷ while (sortList->responseTime <= currTime) { ⑸ OsDeleteNodeSortLink(g_swtmrSortLinkList, sortList); ⑹ SWTMR_CTRL_S *swtmr = LOS_DL_LIST_ENTRY(sortList, SWTMR_CTRL_S, stSortList); OsSwtmrTimeoutHandle(swtmr); needSchedule = TRUE; ⑺ if (LOS_ListEmpty(listObject)) { break; } sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode); } return needSchedule; }
咱们最后看下函数OsSwtmrTimeoutHandle()。⑴处把定时器回调函数写入定时器队列。⑵若是是一次性定时器,会把这个定时器删除,回收到空闲定时器链表,状态设置为未使用状态,而后更新定时器的编号timerId。⑶若是定时器属于周期性定时器,从新启动定时器。⑷若是是一次性定时器但不删除,则把定时器状态设置为建立状态。
STATIC VOID OsSwtmrTimeoutHandle(SWTMR_CTRL_S *swtmr) { SwtmrHandlerItem swtmrHandler; swtmrHandler.handler = swtmr->pfnHandler; swtmrHandler.arg = swtmr->uwArg; ⑴ (VOID)LOS_QueueWriteCopy(g_swtmrHandlerQueue, &swtmrHandler, sizeof(SwtmrHandlerItem), LOS_NO_WAIT); ⑵ if (swtmr->ucMode == LOS_SWTMR_MODE_ONCE) { OsSwtmrDelete(swtmr); if (swtmr->usTimerID < (OS_SWTMR_MAX_TIMERID - LOSCFG_BASE_CORE_SWTMR_LIMIT)) { swtmr->usTimerID += LOSCFG_BASE_CORE_SWTMR_LIMIT; } else { swtmr->usTimerID %= LOSCFG_BASE_CORE_SWTMR_LIMIT; } ⑶ } else if (swtmr->ucMode == LOS_SWTMR_MODE_PERIOD) { OsSwtmrStart(swtmr); ⑷ } else if (swtmr->ucMode == LOS_SWTMR_MODE_NO_SELFDELETE) { swtmr->ucState = OS_SWTMR_STATUS_CREATED; } }
本文带领你们一块儿剖析了鸿蒙轻内核的定时器模块的源代码,包含定时器的结构体、定时器池初始化、定时器建立、删除、启动中止等。感谢阅读,若有任何问题、建议,均可以留言给咱们: https://gitee.com/openharmony/kernel_liteos_m/issues 。为了更容易找到鸿蒙轻内核代码仓,建议访问 https://gitee.com/openharmony/kernel_liteos_m ,关注Watch
、点赞Star
、并Fork
到本身帐户下,谢谢。