摘要:本文通过剖析鸿蒙轻内核定时器模块的源码,把握定时器应用上的差别。

本文分享自华为云社区《鸿蒙轻内核M核源码剖析系列十四 软件定时器Swtmr》,作者:zhushy 。

软件定时器(Software Timer)是基于零碎Tick时钟中断且由软件来模仿的定时器。当通过设定的Tick数后,会触发用户自定义的回调函数。硬件定时器受硬件的限度,数量上不足以满足用户的理论需要。鸿蒙轻内核提供了软件定时器性能能够提供更多的定时器,满足用户需要。

本文通过剖析鸿蒙轻内核定时器模块的源码,把握定时器应用上的差别。本文中所波及的源码,以OpenHarmony LiteOS-M内核为例,均能够在开源站点https://gitee.com/openharmony... 获取。

接下来,咱们看下定时器的构造体,定时器初始化,定时器罕用操作的源代码。

1、定时器构造体定义和罕用宏定义

1.1 定时器构造体定义

在文件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,如下:

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, /* 定时器须要对齐 */};#endifenum 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_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));            }        }    }}

3、定时器罕用操作

3.1 定时器创立

咱们剖析下创立定时器函数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)#elseLITE_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;}

3.2 定时器删除

咱们能够应用函数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}

3.3 定时器启动

创立结束定时器后,咱们能够应用函数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);    }}

3.4 定时器进行

咱们能够应用函数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    }}

4、定时器和Tick工夫关系

定时器退出到超时排序链表后,随时工夫一个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... 。为了更容易找到鸿蒙轻内核代码仓,倡议拜访 https://gitee.com/openharmony... ,关注Watch、点赞Star、并Fork到本人账户下,谢谢。

点击关注,第一工夫理解华为云陈腐技术~