鸿蒙内核阅读笔记-定时器

简介

近期在阅读鸿蒙liteOS_a,由于是初次探索内核的奥秘。将一些阅读的心得进行分享。希望能在作为笔记的同时,也能帮助更多人学习。
感谢图灵大佬的注释项目,使我能够更加快速的理解。
https://weharmony.github.io/

核心模块

核心模块位于:kernel -> base -> core
其中包括:
los_bitmap.c 用于位操作,改变标志位。
los_process.c 用于控制并发、并行、单核多进程、多核多线程的管理
los_sortlik.c 用于排序
los_swtmr.c 用于定时器
los_sys.c 用于时间管理,转换秒与毫秒,了解当前系统运行时间
los_task.c 用于任务状态管理,一个任务代表一个线程,管理其运行状态。
los_tick.c 用于系统时钟、节拍器。

定时器(los_swtmr.c)

介绍

系统定时器个人理解为用来控制系统中断或者定时触发回调函数。

定时器分为三种状态:
1、 OS_SWTMR_STATUS_UNUSED(定时器未使用)
系统在定时器模块初始化时,会将系统中所有定时器资源初始化成该状态。

2、 OS_SWTMR_STATUS_TICKING(定时器处于计数状态)
在定时器创建后调用LOS_SwtmrStart接口启动,定时器将变成该状态,是定时器运行时的状态。

3、 OS_SWTMR_STATUS_CREATED(定时器创建后未启动,或已停止)
定时器创建后,不处于计数状态时,定时器将变成该状态。

软件定时器提供三种模式:
1、单次触发定时器,这类定时器在启动后只会触发一次定时器事件,然后定时器自动删除。

2、周期触发定时器,这类定时器会周期性的触发定时器事件,直到用户手动停止定时器,否则将永远持续执行下去。

3、单次触发定时器,但这类定时器超时触发后不会自动删除,需要调用定时器删除接口删除定时器。

阅读代码

LITE_OS_SEC_BSS SWTMR_CTRL_S    *g_swtmrCBArray = NULL; 
/*
    swtmr = software timer 软件定时器。
    CBArray是阵列。
    合起来叫做:定时器池。
*/
LITE_OS_SEC_BSS UINT8           *g_swtmrHandlerPool = NULL; 
/*
    赋值上软时钟的回调函数,软时钟结束会调用它。
*/
LITE_OS_SEC_BSS LOS_DL_LIST     g_swtmrFreeList; 

/*
    LOS_DL_LIST 这是双向链表,主要使用承上启下。
    定时器通常至少要包含两个成员:一个超时时间(相对时间或者绝对时间)和一个任务回调函数。
    有的时候还可能包含回调函数被执行时需要传入的参数,以及是否重启定时器等信息。
    链表是双向的,则每个定时器包含指向前一个定时器的指针成员。(有点像某区块链)
*/

LITE_OS_SEC_BSS  SPIN_LOCK_INIT(g_swtmrSpin); 
/*
    初始化软时钟自旋锁,只有SMP情况才需要,只要是自旋锁都是用于CPU多核的同步。
    自旋锁是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
    我简单理解自旋锁为控制多处理器并发,控制竞争。
*/
#define SWTMR_LOCK(state)       LOS_SpinLockSave(&g_swtmrSpin, &(state)) 
/*
    持有软时钟自旋锁
    这里定义个SWTMR_LOCK常量,用于锁定软时钟的自旋锁。
*/
#define SWTMR_UNLOCK(state)     LOS_SpinUnlockRestore(&g_swtmrSpin, (state)) 
/*
    释放软时钟自旋锁
    这里定义个SWTMR_LOCK常量,用于解除锁定软时钟的自旋锁。
*/

函数部分

LITE_OS_SEC_TEXT VOID OsSwtmrTask(VOID)
/*
    函数作为软时钟的入口。
*/
{
    
    
    SwtmrHandlerItemPtr swtmrHandlePtr = NULL;
    /*
        在kernel/base/include/los_swtmr_pri.h
        typedef SwtmrHandlerItem *SwtmrHandlerItemPtr;
        指向处理软件计时器超时的回调函数结构的指针的类型。
        个人理解用于定位。
    */
    SwtmrHandlerItem swtmrHandle;
    /*
        SwtmrHandlerItem是定时器响应函数。
    */
    UINT32 ret, swtmrHandlerQueue;
    /*
        swtmrHandlerQueue是定时器处理队列。
    */
    swtmrHandlerQueue = OsPercpuGet()->swtmrHandlerQueue;
    /*
        OsPercpuGet 获取CPU GET之中的定时器超时队列。
    */
    for (;;) {
    
    
        // 死循环获取队列item,一直读干净为止 遍历队列!
        ret = LOS_QueueRead(swtmrHandlerQueue, &swtmrHandlePtr, sizeof(CHAR *), LOS_WAIT_FOREVER);
        // 一个一个读队列
        if ((ret == LOS_OK) && (swtmrHandlePtr != NULL)) {
    
    
            /*
                判断队列未 LOS_OK,以及定位指针被移动不为初始值NULL。
                主要判断队列是否为空和是否完成。
            */
            swtmrHandle.handler = swtmrHandlePtr->handler;
            //超时中断处理函数,也称回调函数
            swtmrHandle.arg = swtmrHandlePtr->arg;
            //回调函数的参数
            (VOID)LOS_MemboxFree(g_swtmrHandlerPool, swtmrHandlePtr);
            //静态释放内存,注意在鸿蒙内核只有软时钟注册用到了静态内存
            if (swtmrHandle.handler != NULL) {
    
    
                // 确认回调函数存在,然后执行回调函数。
                swtmrHandle.handler(swtmrHandle.arg);
                // 回调函数处理函数
            }
        }
    }
}
//创建软时钟任务,每个cpu core都可以拥有自己的软时钟任务
LITE_OS_SEC_TEXT_INIT UINT32 OsSwtmrTaskCreate(VOID)
{
    
    
    UINT32 ret, swtmrTaskID;
    TSK_INIT_PARAM_S swtmrTask;
    UINT32 cpuid = ArchCurrCpuid();//获取当前CPU id
    /*
        创建变量 ret 和 swtmrTaskID 以及swtmrTask,之后获取当前CPU ID。
        操作和当前执行的CPU有关系。
    */

    (VOID)memset_s(&swtmrTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));//清0
    /*
        memset_s为初始化函数。
    */
    swtmrTask.pfnTaskEntry = (TSK_ENTRY_FUNC)OsSwtmrTask;//入口函数
    swtmrTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;//16K默认内核任务栈
    swtmrTask.pcName = "Swt_Task";//任务名称
    swtmrTask.usTaskPrio = 0;//哇塞! 逮到一个最高优先级的任务 @note_thinking 这里应该用 OS_TASK_PRIORITY_HIGHEST 表示
    swtmrTask.uwResved = LOS_TASK_STATUS_DETACHED;//分离模式
    /*
        首先获取入口函数,然后LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE获取默认任务栈的大小,紧接着指定任务名称,设置任务优先级为0(最高优先级),LOS_TASK_STATUS_DETACHED设置任务为自删除状态。
    */
#if (LOSCFG_KERNEL_SMP == YES)
    swtmrTask.usCpuAffiMask   = CPUID_TO_AFFI_MASK(cpuid);//交给当前CPU执行这个任务
#endif
    ret = LOS_TaskCreate(&swtmrTaskID, &swtmrTask);//创建任务并申请调度
    if (ret == LOS_OK) {
    
    
        g_percpu[cpuid].swtmrTaskID = swtmrTaskID;//全局变量记录 软时钟任务ID
        OS_TCB_FROM_TID(swtmrTaskID)->taskStatus |= OS_TASK_FLAG_SYSTEM_TASK;//告知这是一个系统任务
    }
    /*
        调度软时钟任务,执行、申请、记录等几个方面。
    */
    return ret;
}
//回收指定进程的软时钟
LITE_OS_SEC_TEXT_INIT VOID OsSwtmrRecycle(UINT32 processID)
{
    
    
    for (UINT16 index = 0; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++) {
    
    //一个进程往往会有多个定时器
        if (g_swtmrCBArray[index].uwOwnerPid == processID) {
    
    //找到一个
            LOS_SwtmrDelete(index);//删除定时器
        }
    }
    /*
        删除某进程的软时钟,传入进程ID,然后利用进程ID遍历数组。
    */
}
//软时钟初始化 ,注意函数在多CPU情况下会执行多次
LITE_OS_SEC_TEXT_INIT UINT32 OsSwtmrInit(VOID)
{
    
    
    UINT32 size;
    UINT16 index;
    UINT32 ret;
    SWTMR_CTRL_S *swtmr = NULL;
    UINT32 swtmrHandlePoolSize;
    UINT32 cpuid = ArchCurrCpuid();
    /*
        软时钟初始化变量
        size 大小
        index 索引
        ret 中转变量(应该是临时变量)
        *swtmr 用于定位
        swtmrHandlePoolSize 时钟句柄池大小
        ArchCurrCpuid 当前CUPID

    */
    if (cpuid == 0) {
    
    //确保以下代码块由一个CPU执行,g_swtmrCBArray和g_swtmrHandlerPool 是所有CPU共用的
        size = sizeof(SWTMR_CTRL_S) * LOSCFG_BASE_CORE_SWTMR_LIMIT;//申请软时钟内存大小 
        swtmr = (SWTMR_CTRL_S *)LOS_MemAlloc(m_aucSysMem0, size); /* system resident resource */ //常驻内存

        if (swtmr == NULL) {
    
    
            ret = LOS_ERRNO_SWTMR_NO_MEMORY;
            goto ERROR;
        }
        /*
            在申请软时钟之后判断时钟是否结束,如果结束则抛出异常。
        */

        (VOID)memset_s(swtmr, size, 0, size);//清0
        g_swtmrCBArray = swtmr;//软时钟
        LOS_ListInit(&g_swtmrFreeList);//初始化空闲链表
        /*
            上篇文章有笔记,时钟是链表。
        */
        for (index = 0; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++, swtmr++) {
    
    
            swtmr->usTimerID = index;//按顺序赋值
            LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode);//通过sortLinkNode将节点挂到空闲链表 
        }
        /*
            将所有的软时钟挂在链表之上,可能是方便执行吧。
        */
		//想要用静态内存池管理,就必须要使用LOS_MEMBOX_SIZE来计算申请的内存大小,因为需要点前缀内存承载头部信息.
        swtmrHandlePoolSize = LOS_MEMBOX_SIZE(sizeof(SwtmrHandlerItem), OS_SWTMR_HANDLE_QUEUE_SIZE);//计算所有注册函数内存大小
		//规划一片内存区域作为软时钟处理函数的静态内存池。
        g_swtmrHandlerPool = (UINT8 *)LOS_MemAlloc(m_aucSysMem1, swtmrHandlePoolSize); /* system resident resource *///常驻内存
        if (g_swtmrHandlerPool == NULL) {
    
    
            ret = LOS_ERRNO_SWTMR_NO_MEMORY;
            goto ERROR;
        }
        /*
            通过计算所需内存大小,然后申请内存大小,最后常驻内存。紧接着判断g_swtmrHandlerPool是否存在如果不存在则抛出异常。
        */

        ret = LOS_MemboxInit(g_swtmrHandlerPool, swtmrHandlePoolSize, sizeof(SwtmrHandlerItem));//初始化软时钟注册池
        if (ret != LOS_OK) {
    
    
            ret = LOS_ERRNO_SWTMR_HANDLER_POOL_NO_MEM;
            goto ERROR;
        }
        ret = OsSchedSwtmrScanRegister((SchedScan)OsSwtmrScan);
        if (ret != LOS_OK) {
    
    
            goto ERROR;
        }
        /*
            LOS_MemboxInit进行静态内存初始化。返回值ret,先判断初始化是否成功,然后再执行注册扫描并且判断是否成功。
        */
    }
	//每个CPU都会创建一个属于自己的 OS_SWTMR_HANDLE_QUEUE_SIZE 的队列
    ret = LOS_QueueCreate(NULL, OS_SWTMR_HANDLE_QUEUE_SIZE, &g_percpu[cpuid].swtmrHandlerQueue, 0, sizeof(CHAR *));//为当前CPU core 创建软时钟队列 maxMsgSize:sizeof(CHAR *)
    if (ret != LOS_OK) {
    
    
        ret = LOS_ERRNO_SWTMR_QUEUE_CREATE_FAILED;
        goto ERROR;
    }
    /*
        创建当前CPU的时钟队列,以及异常判断。
    */

    ret = OsSwtmrTaskCreate();//每个CPU独自创建属于自己的软时钟任务,统一处理队列
    if (ret != LOS_OK) {
    
    
        ret = LOS_ERRNO_SWTMR_TASK_CREATE_FAILED;
        goto ERROR;
    }

    ret = OsSortLinkInit(&g_percpu[cpuid].swtmrSortLink);//每个CPU独自对自己软时钟链表排序初始化,为啥要排序因为每个定时器的时间不一样,鸿蒙把用时短的排在前面
    if (ret != LOS_OK) {
    
    
        ret = LOS_ERRNO_SWTMR_SORTLINK_CREATE_FAILED;
        goto ERROR;
    }

    return LOS_OK;
ERROR:
    PRINT_ERR("OsSwtmrInit error! ret = %u\n", ret);
    return ret;
}

/*
 * Description: Start Software Timer
 * Input      : swtmr --- Need to start software timer
 */ //开始定时器
LITE_OS_SEC_TEXT VOID OsSwtmrStart(SWTMR_CTRL_S *swtmr)
{
    
    
    UINT32 ticks;
    UINT64 currTime = OsGerCurrSchedTimeCycle();
    /*
        ticks 用于计时器存储
        OsGerCurrSchedTimeCycle 获取调度经过多少周期

    */
    if ((swtmr->uwOverrun == 0) && ((swtmr->ucMode == LOS_SWTMR_MODE_ONCE) ||
        (swtmr->ucMode == LOS_SWTMR_MODE_OPP) ||
        (swtmr->ucMode == LOS_SWTMR_MODE_NO_SELFDELETE))) {
    
    
        ticks = swtmr->uwExpiry;
    } else {
    
    
        ticks = swtmr->uwInterval;
    }
    /*
        在if里面条件情况下 计时器进行存储。
    */
    swtmr->ucState = OS_SWTMR_STATUS_TICKING;

    OsAdd2SortLink(&swtmr->stSortList, currTime, ticks, OS_SORT_LINK_SWTMR);
    if (OS_SCHEDULER_ACTIVE) {
    
    
        OsSchedUpdateExpireTime(currTime);
    }
    /*
        OsAdd2SortLink排序链表插入
    */
    return;
}

/*
 * Description: Delete Software Timer
 * Input      : swtmr --- Need to delete software timer, When using, Ensure that it can't be NULL.
 */
STATIC INLINE VOID OsSwtmrDelete(SWTMR_CTRL_S *swtmr)
{
    
    
    /* insert to free list */
    LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode);//直接插入空闲链表中,回收再利用
    swtmr->ucState = OS_SWTMR_STATUS_UNUSED;//又干净着呢
    swtmr->uwOwnerPid = 0;//谁拥有这个定时器? 是 0号进程, 0号进程出来了,竟然是虚拟的一个进程.用于这类缓冲使用.
}
STATIC INLINE VOID OsWakePendTimeSwtmr(Percpu *cpu, SWTMR_CTRL_S *swtmr)
{
    
    
    LOS_SpinLock(&g_swtmrSpin);
    SwtmrHandlerItemPtr swtmrHandler = (SwtmrHandlerItemPtr)LOS_MemboxAlloc(g_swtmrHandlerPool);
    if (swtmrHandler != NULL) {
    
    
        swtmrHandler->handler = swtmr->pfnHandler;
        swtmrHandler->arg = swtmr->uwArg;

        if (LOS_QueueWrite(cpu->swtmrHandlerQueue, swtmrHandler, sizeof(CHAR *), LOS_NO_WAIT)) {
    
    
            (VOID)LOS_MemboxFree(g_swtmrHandlerPool, swtmrHandler);
        }
    }
    /*
        自旋锁控制
    */
    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_NO_SELFDELETE) {
    
    
        swtmr->ucState = OS_SWTMR_STATUS_CREATED;
    } else {
    
    
        swtmr->uwOverrun++;
        OsSwtmrStart(swtmr);
    }

    LOS_SpinUnlock(&g_swtmrSpin);
}
/*
 * Description: Tick interrupt interface module of software timer
 * Return     : LOS_OK on success or error code on failure
 *///OsSwtmrScan 由系统时钟中断处理函数调用
LITE_OS_SEC_TEXT VOID OsSwtmrScan(VOID)//扫描定时器,如果碰到超时的,就放入超时队

{
    
    
    Percpu *cpu = OsPercpuGet();
    SortLinkAttribute* swtmrSortLink = &OsPercpuGet()->swtmrSortLink;
    LOS_DL_LIST *listObject = &swtmrSortLink->sortLink;
    /*
        OsPercpuGet 用来获取当前CPU信息
        swtmrSortLink CPU需要处理的定时器链表
        *listObject 指向其链表位置
    */

    /*
     * it needs to be carefully coped with, since the swtmr is in specific sortlink
     * while other cores still has the chance to process it, like stop the timer.
     */
    LOS_SpinLock(&cpu->swtmrSortLinkSpin);

    if (LOS_ListEmpty(listObject)) {
    
    
        LOS_SpinUnlock(&cpu->swtmrSortLinkSpin);
        return;
    }
    /*
        LOS_SpinLock和LOS_SpinUnlock是自旋锁控制
    */
    SortLinkList *sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
    /*
        LOS_DL_LIST_ENTRY获取双向链表节点所在的业务结构体的内存地址。
    */
    
    UINT64 currTime = OsGerCurrSchedTimeCycle();
    while (sortList->responseTime <= currTime) {
    
    
        sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
        OsDeleteNodeSortLink(swtmrSortLink, sortList);

        SWTMR_CTRL_S *swtmr = LOS_DL_LIST_ENTRY(sortList, SWTMR_CTRL_S, stSortList);
        LOS_SpinUnlock(&cpu->swtmrSortLinkSpin);
        /*
            自旋锁控制。
        */

        OsWakePendTimeSwtmr(cpu, swtmr);

        LOS_SpinLock(&cpu->swtmrSortLinkSpin);
        if (LOS_ListEmpty(listObject)) {
    
    
            break;
        }

        sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode); 
        /*
            创建链表
        */
    }

    LOS_SpinUnlock(&cpu->swtmrSortLinkSpin);
    /*
        currTime 获得当前的时间周期
        循环中判断如果响应时间小于当前的时间周期,然后获取全部双向链表LOS_DL_LIST_ENTRY,删除节点OsDeleteNodeSortLink。
    */
}

/*
 * Description: Get next timeout
 * Return     : Count of the Timer list
 */
LITE_OS_SEC_TEXT UINT32 OsSwtmrGetNextTimeout(VOID)//获取下一个timeout
{
    
    
    return OsSortLinkGetNextExpireTime(&OsPercpuGet()->swtmrSortLink);
}

/*
 * Description: Stop of Software Timer interface
 * Input      : swtmr --- the software timer contrl handler
 */
LITE_OS_SEC_TEXT STATIC VOID OsSwtmrStop(SWTMR_CTRL_S *swtmr)
{
    
    
    OsDeleteSortLink(&swtmr->stSortList, OS_SORT_LINK_SWTMR);
    /*
        删除节点的链接。
    */

    swtmr->ucState = OS_SWTMR_STATUS_CREATED;
    swtmr->uwOverrun = 0;

    if (OS_SCHEDULER_ACTIVE) {
    
    
        OsSchedUpdateExpireTime(OsGerCurrSchedTimeCycle());
        /*
            更新过期时间。
        */
    }
}

/*
 * Description: Get next software timer expiretime
 * Input      : swtmr --- the software timer contrl handler
 */
LITE_OS_SEC_TEXT STATIC UINT32 OsSwtmrTimeGet(const SWTMR_CTRL_S *swtmr)
{
    
    
    return OsSortLinkGetTargetExpireTime(&swtmr->stSortList);
}
//创建定时器,设置定时器的定时时长、定时器模式、回调函数,并返回定时器ID
LITE_OS_SEC_TEXT_INIT UINT32 LOS_SwtmrCreate(UINT32 interval,
                                             UINT8 mode,
                                             SWTMR_PROC_FUNC handler,
                                             UINT16 *swtmrID,
                                             UINTPTR arg)
{
    
    
    SWTMR_CTRL_S *swtmr = NULL;
    UINT32 intSave;
    SortLinkList *sortList = NULL;

    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;
        /*
            入参的软件定时器ID指针为NULL。
        */
    }

    SWTMR_LOCK(intSave);
    if (LOS_ListEmpty(&g_swtmrFreeList)) {
    
    //空闲链表不能为空
        SWTMR_UNLOCK(intSave);
        return LOS_ERRNO_SWTMR_MAXSIZE;
        /*
            软件定时器个数超过最大值
        */
    }

    sortList = LOS_DL_LIST_ENTRY(g_swtmrFreeList.pstNext, SortLinkList, sortLinkNode);
    swtmr = LOS_DL_LIST_ENTRY(sortList, SWTMR_CTRL_S, stSortList);
    LOS_ListDelete(LOS_DL_LIST_FIRST(&g_swtmrFreeList)); 
    /*删除指定节点*/
    SWTMR_UNLOCK(intSave);

    swtmr->uwOwnerPid = OsCurrProcessGet()->processID;//定时器进程归属设定
    swtmr->pfnHandler = handler;//时间到了的回调函数
    swtmr->ucMode = mode;	//定时器模式
    swtmr->uwOverrun = 0;
    swtmr->uwInterval = interval;	//周期性超时间隔
    swtmr->uwExpiry = interval;		//一次性超时间隔
    swtmr->uwArg = arg;				//回调函数的参数
    swtmr->ucState = OS_SWTMR_STATUS_CREATED;	//已创建状态
    SET_SORTLIST_VALUE(&swtmr->stSortList, OS_SORT_LINK_INVALID_TIME);
    *swtmrID = swtmr->usTimerID;

    return LOS_OK;
}
//接口函数 启动定时器       参数定时任务ID
LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStart(UINT16 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; /*入参的软件定时器ID不正确*/
    }

    swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;//取模
    swtmr = g_swtmrCBArray + swtmrCBID;//获取定时器控制结构体

    SWTMR_LOCK(intSave);
    if (swtmr->usTimerID != swtmrID) {
    
    //ID必须一样
        SWTMR_UNLOCK(intSave);
        return LOS_ERRNO_SWTMR_ID_INVALID;
    }

    switch (swtmr->ucState) {
    
    //判断定时器状态
        case OS_SWTMR_STATUS_UNUSED:
            ret = LOS_ERRNO_SWTMR_NOT_CREATED;
            break;
        /* 如果定时器的状态为启动中,应先停止定时器再重新启动
         * If the status of swtmr is timing, it should stop the swtmr first,
         * then start the swtmr again.
         */
        case OS_SWTMR_STATUS_TICKING://正在计数的定时器
            OsSwtmrStop(swtmr);//先停止定时器,注意这里没有break;,在OsSwtmrStop中状态将会回到了OS_SWTMR_STATUS_CREATED 接下来就是执行启动了
            /* fall-through */
        case OS_SWTMR_STATUS_CREATED://已经创建好了
            OsSwtmrStart(swtmr);//启动定时器
            break;
        default:
            ret = LOS_ERRNO_SWTMR_STATUS_INVALID;
            break;
    }

    SWTMR_UNLOCK(intSave);
    return ret;
}
//接口函数 停止定时器          参数定时任务ID
LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStop(UINT16 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;
        /*
            判断编号如果到达或者超多最大值,然后返回传入参数失败。 后面的方式和前面的相差不大。
        */
    }

    swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;//取模
    swtmr = g_swtmrCBArray + swtmrCBID;//获取定时器控制结构体
    SWTMR_LOCK(intSave);

    if (swtmr->usTimerID != swtmrID) {
    
    //ID必须一样
        SWTMR_UNLOCK(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;
    }

    SWTMR_UNLOCK(intSave);
    return ret;
}
//接口函数 获得软件定时器剩余Tick数 通过 *tick 带走 
LITE_OS_SEC_TEXT UINT32 LOS_SwtmrTimeGet(UINT16 swtmrID, UINT32 *tick)
{
    
    
    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;
    }

    if (tick == NULL) {
    
    
        return LOS_ERRNO_SWTMR_TICK_PTR_NULL;
    }

    swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;//取模
    swtmr = g_swtmrCBArray + swtmrCBID;//获取定时器控制结构体
    SWTMR_LOCK(intSave);

    if (swtmr->usTimerID != swtmrID) {
    
    //ID必须一样
        SWTMR_UNLOCK(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://正在计数的定时器
            *tick = OsSwtmrTimeGet(swtmr);//获取
            break;
        default:
            ret = LOS_ERRNO_SWTMR_STATUS_INVALID;
            break;
    }
    SWTMR_UNLOCK(intSave);
    return ret;
}
//接口函数 删除定时器
LITE_OS_SEC_TEXT UINT32 LOS_SwtmrDelete(UINT16 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;
    }

    swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;//取模
    swtmr = g_swtmrCBArray + swtmrCBID;//获取定时器控制结构体
    SWTMR_LOCK(intSave);

    if (swtmr->usTimerID != swtmrID) {
    
    //ID必须一样
        SWTMR_UNLOCK(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://正在计数就先停止再删除,这里没有break;
            OsSwtmrStop(swtmr);
            /* fall-through */
        case OS_SWTMR_STATUS_CREATED://再删除定时器
            OsSwtmrDelete(swtmr);
            break;
        default:
            ret = LOS_ERRNO_SWTMR_STATUS_INVALID;
            break;
    }

    SWTMR_UNLOCK(intSave);
    return ret;
}

#endif /* (LOSCFG_BASE_CORE_SWTMR == YES) */

猜你喜欢

转载自blog.csdn.net/qq_35476650/article/details/118185244
今日推荐