diff --git a/core/los_smp.c b/core/los_smp.c index 1500227..21bc056 100644 --- a/core/los_smp.c +++ b/core/los_smp.c @@ -40,7 +40,7 @@ #ifdef LOSCFG_KERNEL_SMP STATIC struct SmpOps *g_smpOps = NULL; - +/// 多核中次级CPU核初始化,每个核都会调用一次 STATIC VOID OsSmpSecondaryInit(VOID *arg) { UNUSED(arg); @@ -60,7 +60,7 @@ STATIC VOID OsSmpSecondaryInit(VOID *arg) OsSchedStart(); } - +/// 设置多核操作接口, 通过外部注册 VOID LOS_SmpOpsSet(struct SmpOps *ops) { g_smpOps = ops; diff --git a/core/los_swtmr.c b/core/los_swtmr.c index dde50c6..314acfb 100644 --- a/core/los_swtmr.c +++ b/core/los_swtmr.c @@ -1,4 +1,67 @@ -/* +/*! +* @file los_swtmr.c +* @brief 软定时器主文件 +* @details +* @attention @verbatim +基本概念 + 软件定时器,是基于系统Tick时钟中断且由软件来模拟的定时器。当经过设定的Tick数后,会触发用户自定义的回调函数。 + 硬件定时器受硬件的限制,数量上不足以满足用户的实际需求。因此为了满足用户需求,提供更多的定时器, + 软件定时器功能,支持如下特性: + 创建软件定时器。 + 启动软件定时器。 + 停止软件定时器。 + 删除软件定时器。 + 获取软件定时器剩余Tick数。 + 可配置支持的软件定时器个数。 + + 运作机制 + 软件定时器是系统资源,在模块初始化的时候已经分配了一块连续内存。 + 软件定时器使用了系统的一个队列和一个任务资源,软件定时器的触发遵循队列规则, + 先进先出。定时时间短的定时器总是比定时时间长的靠近队列头,满足优先触发的准则。 + 软件定时器以Tick为基本计时单位,当创建并启动一个软件定时器时,Huawei LiteOS会根据 + 当前系统Tick时间及设置的定时时长确定该定时器的到期Tick时间,并将该定时器控制结构挂入计时全局链表。 + 当Tick中断到来时,在Tick中断处理函数中扫描软件定时器的计时全局链表,检查是否有定时器超时, + 若有则将超时的定时器记录下来。Tick中断处理函数结束后,软件定时器任务(优先级为最高) + 被唤醒,在该任务中调用已经记录下来的定时器的回调函数。 + + 定时器状态 + OS_SWTMR_STATUS_UNUSED(定时器未使用) + 系统在定时器模块初始化时,会将系统中所有定时器资源初始化成该状态。 + + OS_SWTMR_STATUS_TICKING(定时器处于计数状态) + 在定时器创建后调用LOS_SwtmrStart接口启动,定时器将变成该状态,是定时器运行时的状态。 + + OS_SWTMR_STATUS_CREATED(定时器创建后未启动,或已停止) + 定时器创建后,不处于计数状态时,定时器将变成该状态。 + + 软件定时器提供了三类模式: + 单次触发定时器,这类定时器在启动后只会触发一次定时器事件,然后定时器自动删除。 + 周期触发定时器,这类定时器会周期性的触发定时器事件,直到用户手动停止定时器,否则将永远持续执行下去。 + 单次触发定时器,但这类定时器超时触发后不会自动删除,需要调用定时器删除接口删除定时器。 + + 使用场景 + 创建一个单次触发的定时器,超时后执行用户自定义的回调函数。 + 创建一个周期性触发的定时器,超时后执行用户自定义的回调函数。 + + 软件定时器的典型开发流程 + 通过make menuconfig配置软件定时器 + 创建定时器LOS_SwtmrCreate,设置定时器的定时时长、定时器模式、超时后的回调函数。 + 启动定时器LOS_SwtmrStart。 + 获得软件定时器剩余Tick数LOS_SwtmrTimeGet。 + 停止定时器LOS_SwtmrStop。 + 删除定时器LOS_SwtmrDelete。 + + 注意事项 + 软件定时器的回调函数中不应执行过多操作,不建议使用可能引起任务挂起或者阻塞的接口或操作, + 如果使用会导致软件定时器响应不及时,造成的影响无法确定。 + 软件定时器使用了系统的一个队列和一个任务资源。软件定时器任务的优先级设定为0,且不允许修改 。 + 系统可配置的软件定时器个数是指:整个系统可使用的软件定时器总个数,并非用户可使用的软件定时器个数。 + 例如:系统多占用一个软件定时器,那么用户能使用的软件定时器资源就会减少一个。 + 创建单次不自删除属性的定时器,用户需要自行调用定时器删除接口删除定时器,回收定时器资源,避免资源泄露。 + 软件定时器的定时精度与系统Tick时钟的周期有关。 + @endverbatim +以上内容整理自CSDN +*//* * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. * @@ -54,9 +117,9 @@ LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_swtmrSpin); LITE_OS_SEC_TEXT VOID OsSwtmrTask(VOID) { - SwtmrHandlerItemPtr swtmrHandlePtr = NULL; - SwtmrHandlerItem swtmrHandle; - UINT32 ret, swtmrHandlerQueue; + SwtmrHandlerItemPtr swtmrHandlePtr = NULL;///< 初始化软时钟自旋锁,只有SMP情况才需要,只要是自旋锁都是用于CPU多核的同步 + SwtmrHandlerItem swtmrHandle;///< 持有软时钟自旋锁 + UINT32 ret, swtmrHandlerQueue;///< 释放软时钟自旋锁 swtmrHandlerQueue = OsPercpuGet()->swtmrHandlerQueue; for (;;) { @@ -71,23 +134,24 @@ LITE_OS_SEC_TEXT VOID OsSwtmrTask(VOID) } } } - +///创建软时钟任务,每个cpu core都可以拥有自己的软时钟任务 LITE_OS_SEC_TEXT_INIT UINT32 OsSwtmrTaskCreate(VOID) { UINT32 ret, swtmrTaskID; TSK_INIT_PARAM_S swtmrTask; UINT32 cpuid = ArchCurrCpuid(); - (VOID)memset_s(&swtmrTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); - swtmrTask.pfnTaskEntry = (TSK_ENTRY_FUNC)OsSwtmrTask; - swtmrTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; - swtmrTask.pcName = "Swt_Task"; + (VOID)memset_s(&swtmrTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));//清0 + swtmrTask.pfnTaskEntry = (TSK_ENTRY_FUNC)OsSwtmrTask;//入口函数 + swtmrTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;//16K默认内核任务栈 + swtmrTask.pcName = "Swt_Task";//任务名称 swtmrTask.usTaskPrio = 0; swtmrTask.uwResved = LOS_TASK_STATUS_DETACHED; #ifdef LOSCFG_KERNEL_SMP - swtmrTask.usCpuAffiMask = CPUID_TO_AFFI_MASK(cpuid); + swtmrTask.usCpuAffiMask = CPUID_TO_AFFI_MASK(cpuid);//交给当前CPU执行这个任务 + #endif - ret = LOS_TaskCreate(&swtmrTaskID, &swtmrTask); + ret = LOS_TaskCreate(&swtmrTaskID, &swtmrTask);//创建任务并申请调度 if (ret == LOS_OK) { g_percpu[cpuid].swtmrTaskID = swtmrTaskID; OS_TCB_FROM_TID(swtmrTaskID)->taskStatus |= OS_TASK_FLAG_SYSTEM_TASK; @@ -95,7 +159,7 @@ LITE_OS_SEC_TEXT_INIT UINT32 OsSwtmrTaskCreate(VOID) return ret; } - +///回收指定进程的软时钟 LITE_OS_SEC_TEXT_INIT VOID OsSwtmrRecycle(UINT32 processID) { for (UINT16 index = 0; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++) { @@ -104,7 +168,7 @@ LITE_OS_SEC_TEXT_INIT VOID OsSwtmrRecycle(UINT32 processID) } } } - +///软时钟初始化 ,注意函数在多CPU情况下会执行多次 LITE_OS_SEC_TEXT_INIT UINT32 OsSwtmrInit(VOID) { UINT32 size; @@ -121,16 +185,15 @@ LITE_OS_SEC_TEXT_INIT UINT32 OsSwtmrInit(VOID) goto ERROR; } - (VOID)memset_s(swtmr, size, 0, size); - g_swtmrCBArray = swtmr; - LOS_ListInit(&g_swtmrFreeList); + (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); + swtmr->usTimerID = index;//按顺序赋值 + LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode);//通过sortLinkNode将节点挂到空闲链表 } - - swtmrHandlePoolSize = LOS_MEMBOX_SIZE(sizeof(SwtmrHandlerItem), OS_SWTMR_HANDLE_QUEUE_SIZE); - + //想要用静态内存池管理,就必须要使用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; @@ -314,7 +377,7 @@ 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, @@ -354,19 +417,19 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_SwtmrCreate(UINT32 interval, SWTMR_UNLOCK(intSave); swtmr->uwOwnerPid = OsCurrProcessGet()->processID; - swtmr->pfnHandler = handler; - swtmr->ucMode = mode; + swtmr->pfnHandler = handler;//时间到了的回调函数 + swtmr->ucMode = mode; //定时器模式 swtmr->uwOverrun = 0; - swtmr->uwInterval = interval; - swtmr->uwExpiry = interval; - swtmr->uwArg = arg; - swtmr->ucState = OS_SWTMR_STATUS_CREATED; + 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; OsHookCall(LOS_HOOK_TYPE_SWTMR_CREATE, swtmr); return LOS_OK; } - +///接口函数 启动定时器 参数定时任务ID LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStart(UINT16 swtmrID) { SWTMR_CTRL_S *swtmr = NULL; @@ -379,24 +442,24 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStart(UINT16 swtmrID) } swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT; - swtmr = g_swtmrCBArray + swtmrCBID; + swtmr = g_swtmrCBArray + swtmrCBID;//获取定时器控制结构体 SWTMR_LOCK(intSave); - if (swtmr->usTimerID != swtmrID) { + if (swtmr->usTimerID != swtmrID) {//ID必须一样 SWTMR_UNLOCK(intSave); return LOS_ERRNO_SWTMR_ID_INVALID; } - switch (swtmr->ucState) { + 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); + case OS_SWTMR_STATUS_TICKING://正在计数的定时器 + OsSwtmrStop(swtmr);//先停止定时器,注意这里没有break;,在OsSwtmrStop中状态将会回到了OS_SWTMR_STATUS_CREATED 接下来就是执行启动了 /* fall-through */ case OS_SWTMR_STATUS_CREATED: swtmr->startTime = OsGetCurrSchedTimeCycle(); @@ -411,7 +474,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStart(UINT16 swtmrID) OsHookCall(LOS_HOOK_TYPE_SWTMR_START, swtmr); return ret; } - +///接口函数 停止定时器 参数定时任务ID LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStop(UINT16 swtmrID) { SWTMR_CTRL_S *swtmr = NULL; @@ -424,7 +487,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStop(UINT16 swtmrID) } swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT; - swtmr = g_swtmrCBArray + swtmrCBID; + swtmr = g_swtmrCBArray + swtmrCBID;//获取定时器控制结构体 SWTMR_LOCK(intSave); if (swtmr->usTimerID != swtmrID) { @@ -432,15 +495,15 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStop(UINT16 swtmrID) return LOS_ERRNO_SWTMR_ID_INVALID; } - switch (swtmr->ucState) { + switch (swtmr->ucState) {//判断定时器状态 case OS_SWTMR_STATUS_UNUSED: - ret = LOS_ERRNO_SWTMR_NOT_CREATED; + ret = LOS_ERRNO_SWTMR_NOT_CREATED;//返回没有创建 break; case OS_SWTMR_STATUS_CREATED: - ret = LOS_ERRNO_SWTMR_NOT_STARTED; + ret = LOS_ERRNO_SWTMR_NOT_STARTED;//返回没有开始 break; - case OS_SWTMR_STATUS_TICKING: - OsSwtmrStop(swtmr); + case OS_SWTMR_STATUS_TICKING:/正在计数 + SwtmrStop(swtmr);//执行正在停止定时器操作 break; default: ret = LOS_ERRNO_SWTMR_STATUS_INVALID; @@ -451,7 +514,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStop(UINT16 swtmrID) OsHookCall(LOS_HOOK_TYPE_SWTMR_STOP, swtmr); return ret; } - +///接口函数 获得软件定时器剩余Tick数 通过 *tick 带走 LITE_OS_SEC_TEXT UINT32 LOS_SwtmrTimeGet(UINT16 swtmrID, UINT32 *tick) { SWTMR_CTRL_S *swtmr = NULL; @@ -492,7 +555,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrTimeGet(UINT16 swtmrID, UINT32 *tick) SWTMR_UNLOCK(intSave); return ret; } - +///接口函数 删除定时器 LITE_OS_SEC_TEXT UINT32 LOS_SwtmrDelete(UINT16 swtmrID) { SWTMR_CTRL_S *swtmr = NULL; @@ -517,7 +580,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_SwtmrDelete(UINT16 swtmrID) case OS_SWTMR_STATUS_UNUSED: ret = LOS_ERRNO_SWTMR_NOT_CREATED; break; - case OS_SWTMR_STATUS_TICKING: + case OS_SWTMR_STATUS_TICKING://正在计数就先停止再删除,这里没有break; OsSwtmrStop(swtmr); /* fall-through */ case OS_SWTMR_STATUS_CREATED: