Abstract: This article analyzes the source code of the Hongmeng light kernel timer module to grasp the difference in timer usage.
This article is shared from the Huawei Cloud Community " Light Kernel M Core Source Code Analysis Series Fourteen Software Timer Swtmr ", author: zhushy.
Software Timer (Software Timer) is a timer based on the system Tick clock interrupt and simulated by software. After the set number of ticks, a user-defined callback function will be triggered. The hardware timer is limited by the hardware, and the number is not enough to meet the actual needs of users. Hongmeng Light Core provides a software timer function that can provide more timers to meet user needs.
This article analyzes the source code of the Hongmeng light kernel timer module to grasp the difference in timer usage. The source code involved in this article, taking the OpenHarmony LiteOS-M kernel as an example, can be obtained from the open source site https://gitee.com/openharmony/kernel_liteos_m .
Next, we look at the timer structure, timer initialization, and the source code of the timer's common operations.
1. Timer structure definition and common macro definition
1.1 Timer structure definition
The timer control block structure defined in the file kernel\include\los_swtmr.h is SWTMR_CTRL_S, and the source code of the structure is as follows. The timer state.ucState takes the value OS_SWTMR_STATUS_UNUSED, OS_SWTMR_STATUS_CREATED or OS_SWTMR_STATUS_TICKING, and the timer mode.mode takes the value LOS_SWTMR_MODE_ONCE, LOS_SWTMR_MODE_PERIOD or LOS_SWTMR_MODE_NO_SELFDELETE. See the comment section for the explanation of other structure members.
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;
In addition, a structure SwtmrHandlerItem is separately defined for the callback function and its parameters, as follows:
typedef struct {
SWTMR_PROC_FUNC handler; /**< 定时器超时回调函数 */
UINTPTR arg; /**< 定时器超时回调函数参数 */
} SwtmrHandlerItem;
1.2 Commonly used macro definitions of timers
The timer header file kernel\include\los_swtmr.h also provides related enumerations and macros. The macro definition OS_SWT_FROM_SID of the timer control block obtained from the timer pool is as follows:
#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. Timer initialization
The timer is turned on by default in the kernel, and the user can turn it off through the macro LOSCFG_BASE_CORE_SWTMR. When the timer is turned on, when the system starts, call OsSwtmrInit() in kernel\src\los_init.c to initialize the timer module. Next, we analyze the code of timer initialization.
(1) If the timer alignment macro LOSCFG_BASE_CORE_SWTMR_ALIGN is turned on, the g_swtmrAlignID array is cleared. The number of timers is defined by the macro LOSCFG_BASE_CORE_SWTMR_LIMIT. (2) The memory size required by the timer pool is calculated, and then memory is applied for the timer. If the application fails, an error is returned. (3) Initialize the idle timer linked list g_swtmrFreeList, and maintain unused timers. Each timer is cyclically initialized, the index timerId is designated for each timer node, and the timer control block points to the next timer control block in turn.
⑷The code creates a queue for the timer, the message size of the queue OS_SWTMR_HANDLE_QUEUE_SIZE is equal to the number of timers LOSCFG_BASE_CORE_SWTMR_LIMIT, the maximum size of the message content sizeof(SwtmrHandlerItem). Later, we will analyze the specific message when the timer queue reads and writes the message. (5) Call the function OsSwtmrTaskCreate() to create a timer task. The timer task has the highest priority. The entry function of the task is OsSwtmrTask(), which will be analyzed later. ⑹Initialize the timer sorting list. After analyzing the previous articles in the source code analysis series, you can read the chapter on the data structure of the sorting list. ⑺ Register the timer scan function 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;
}
Let's look at the entry function of the timer task as OsSwtmrTask(). ⑴Permanent for loop, the queue will block when no data is read, because the priority is relatively high, the task will be executed when the timer queue has data. Read the timer processing function address from the timer queue into the pointer address &swtmrHandle, and the read length is sizeof(SwtmrHandlerItem). After successful reading, get the timer callback function and its parameters, and then execute the timer callback function at (2). Record the execution time of the timer callback function, and judge whether the execution time is overtime at the place (3). If it is overtime, print a warning message.
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. Common timer operations
3.1 Timer creation
We analyze the code to create the timer function LOS_SwtmrCreate(). Regardless of the timer alignment LOSCFG_BASE_CORE_SWTMR_ALIGN. First look at the function parameters, interval is the timer execution time interval, mode is the created timer mode, handler and arg are the timer callback function and its parameters. swtmrId is the timer number.
(1) Check the incoming parameter timer timeout interval, timer mode, callback function, and timer number. (2) Determine whether the idle timer pool is empty, if it is empty, an error will be returned, and the timer cannot be created. (3) If the timer is not empty, obtain the timer control block swtmr. ⑷Initialize the timer control block information. (5) Initialize the response time responseTime of the timer sorted linked list node to -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;
}
3.2 Timer delete
We can use the function LOS_SwtmrDelete (UINT32 swtmrId) to delete the timer. Let's look at how to delete the timer by analyzing the source code.
(1) It is judged whether the timer swtmrId exceeds OS_SWTMR_MAX_TIMERID, and if it exceeds, an error code is returned. If there is no problem with the timer number, obtain the timer control block LosSwtmrCB *swtmr. (2) It is judged whether the swtmrId of the timer to be deleted matches or not, and an error code is returned if it does not match. (3) The state of the timer is judged. If the timer timer is not created, it cannot be deleted. If the timer is running, you need to stop OsSwtmrStop(swtmr) first, and then delete 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;
}
Next, we continue to see how to call the function OsSwtmrDelete(swtmr) to delete the timer. The function is particularly simple. Put the timer into the head of the idle timer linked list g_swtmrFreeList, and then change the timer state to the unused state to complete the deletion.
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 Timer start
After the timer is created, we can use the function LOS_SwtmrStart (UINT32 swtmrId) to start the timer. Let's see how to start the timer by analyzing the source code.
(1) It is judged whether the timer swtmrId exceeds OS_SWTMR_MAX_TIMERID, and if it exceeds, an error code is returned. If there is no problem with the timer number, obtain the timer control block LosSwtmrCB *swtmr. (2) It is judged whether the swtmrId of the timer to be started matches or not, an error code is returned if it does not match. (3) The state of the timer is judged. If the timer timer is not created, it cannot be started. If the timer is counting, you need to stop OsSwtmrStop(swtmr) first, and then start 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;
}
Next, we continue to see how to call the function OsSwtmrStart (swtmr) to start the timer. The function is particularly simple, ⑴Set the timer's waiting timeout time, and change the timer status to timing. (2) Insert the timer into the timeout sorted list. If task scheduling has been enabled, modify the expiration time.
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 Timer stop
We can use the function LOS_SwtmrStop (UINT32 swtmrId) to stop the timer. Let's see how to stop the timer by analyzing the source code.
(1) It is judged whether the timer swtmrId exceeds OS_SWTMR_MAX_TIMERID, and if it exceeds, an error code is returned. If there is no problem with the timer number, obtain the timer control block LosSwtmrCB *swtmr. (2) It is judged whether the timer swtmrId to be started matches or not, and an error code is returned if it does not match. (3) Judging the status of the timer. If the timer timer has not been created, has not been started, it cannot be stopped. If the timer is running, it will continue to call OsSwtmrStop(swtmr) to stop the timer.
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;
}
Next, we continue to see how to call the function OsSwtmrStop (swtmr) to stop the timer. The function is particularly simple, (1) delete the timer's sorted linked list node from the sorted linked list, and change the state of the timer. ⑵If task scheduling has been enabled, modify the expiration time.
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. The relationship between timer and Tick time
After the timer is added to the timeout sorted list, one tick and one tick elapse at any time, and it is necessary to constantly check whether the timer expires. From the previous article, it is known that every time the system goes through a tick, the system will call the Tick interrupt processing function OsTickHandler(), which will call the timer scan function OsSwtmrScan() to scan and update the timer time. Let's look at the code of OsSwtmrScan().
(1) Get the linked list node listObject of the timeout sorted linked list at ⑵ judge whether the sorted linked list is empty, and return if it is empty. (3) Get the next linked list node sortList of the sort linked list. ⑷ Loop traversing the linked list nodes whose response time is less than or equal to the current time on the timeout sorted linked list, which means that the timer expires and the callback function of the timer needs to be processed. ⑸Delete the timeout node from the timeout sorting list, ⑹Get the timer control block SWTMR_CTRL_S *swtmr, call the function OsSwtmrTimeoutHandle(swtmr) to execute the timer callback function, and set the flag needSchedule that needs to be scheduled. ⑺ If the timeout sorting list is empty, the loop is terminated.
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;
}
We finally look at the function OsSwtmrTimeoutHandle(). ⑴ Write the timer callback function into the timer queue. ⑵If it is a one-time timer, it will delete the timer, recycle it to the idle timer list, set the status to unused, and then update the timer ID timerId. (3) If the timer is a periodic timer, restart the timer. ⑷ If it is a one-time timer but not deleted, set the timer state to the created state.
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;
}
}
summary
This article led everyone to analyze the source code of the timer module of the Hongmeng Light Core, including the structure of the timer, the initialization of the timer pool, the creation, deletion, and start and stop of the timer. Thanks for reading. If you have any questions or suggestions, you can leave a message to us: https://gitee.com/openharmony/kernel_liteos_m/issues . light kernel code warehouse easier, it is recommended to visit 1610a4200b9127 https://gitee.com/openharmony/kernel_liteos_m , follow Watch, like Star, and Fork to your account, thank you.
Click to follow, and learn about Huawei Cloud's fresh technology for the first time~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。