• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this list of
9  *    conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12  *    of conditions and the following disclaimer in the documentation and/or other materials
13  *    provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16  *    to endorse or promote products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "los_swtmr_pri.h"
33 #include "los_init.h"
34 #include "los_process_pri.h"
35 #include "los_queue_pri.h"
36 #include "los_sched_pri.h"
37 #include "los_sortlink_pri.h"
38 #include "los_task_pri.h"
39 #include "los_hook.h"
40 
41 #ifdef LOSCFG_BASE_CORE_SWTMR_ENABLE
42 #if (LOSCFG_BASE_CORE_SWTMR_LIMIT <= 0)
43 #error "swtmr maxnum cannot be zero"
44 #endif /* LOSCFG_BASE_CORE_SWTMR_LIMIT <= 0 */
45 
46 STATIC INLINE VOID SwtmrDelete(SWTMR_CTRL_S *swtmr);
47 STATIC INLINE UINT64 SwtmrToStart(SWTMR_CTRL_S *swtmr, UINT16 cpuid);
48 
49 LITE_OS_SEC_BSS SWTMR_CTRL_S    *g_swtmrCBArray = NULL;     /* First address in Timer memory space */
50 LITE_OS_SEC_BSS UINT8           *g_swtmrHandlerPool = NULL; /* Pool of Swtmr Handler */
51 LITE_OS_SEC_BSS LOS_DL_LIST     g_swtmrFreeList;            /* Free list of Software Timer */
52 
53 /* spinlock for swtmr module, only available on SMP mode */
54 LITE_OS_SEC_BSS  SPIN_LOCK_INIT(g_swtmrSpin);
55 #define SWTMR_LOCK(state)       LOS_SpinLockSave(&g_swtmrSpin, &(state))
56 #define SWTMR_UNLOCK(state)     LOS_SpinUnlockRestore(&g_swtmrSpin, (state))
57 
58 typedef struct {
59     SortLinkAttribute swtmrSortLink;
60     LosTaskCB         *swtmrTask;           /* software timer task id */
61     LOS_DL_LIST       swtmrHandlerQueue;     /* software timer timeout queue id */
62 } SwtmrRunqueue;
63 
64 STATIC SwtmrRunqueue g_swtmrRunqueue[LOSCFG_KERNEL_CORE_NUM];
65 
66 #ifdef LOSCFG_SWTMR_DEBUG
67 #define OS_SWTMR_PERIOD_TO_CYCLE(period) (((UINT64)(period) * OS_NS_PER_TICK) / OS_NS_PER_CYCLE)
68 STATIC SwtmrDebugData *g_swtmrDebugData = NULL;
69 
OsSwtmrDebugDataUsed(UINT32 swtmrID)70 BOOL OsSwtmrDebugDataUsed(UINT32 swtmrID)
71 {
72     if (swtmrID > LOSCFG_BASE_CORE_SWTMR_LIMIT) {
73         return FALSE;
74     }
75 
76     return g_swtmrDebugData[swtmrID].swtmrUsed;
77 }
78 
OsSwtmrDebugDataGet(UINT32 swtmrID,SwtmrDebugData * data,UINT32 len,UINT8 * mode)79 UINT32 OsSwtmrDebugDataGet(UINT32 swtmrID, SwtmrDebugData *data, UINT32 len, UINT8 *mode)
80 {
81     UINT32 intSave;
82     errno_t ret;
83 
84     if ((swtmrID > LOSCFG_BASE_CORE_SWTMR_LIMIT) || (data == NULL) ||
85         (mode == NULL) || (len < sizeof(SwtmrDebugData))) {
86         return LOS_NOK;
87     }
88 
89     SWTMR_CTRL_S *swtmr = &g_swtmrCBArray[swtmrID];
90     SWTMR_LOCK(intSave);
91     ret = memcpy_s(data, len, &g_swtmrDebugData[swtmrID], sizeof(SwtmrDebugData));
92     *mode = swtmr->ucMode;
93     SWTMR_UNLOCK(intSave);
94     if (ret != EOK) {
95         return LOS_NOK;
96     }
97     return LOS_OK;
98 }
99 #endif
100 
SwtmrDebugDataInit(VOID)101 STATIC VOID SwtmrDebugDataInit(VOID)
102 {
103 #ifdef LOSCFG_SWTMR_DEBUG
104     UINT32 size = sizeof(SwtmrDebugData) * LOSCFG_BASE_CORE_SWTMR_LIMIT;
105     g_swtmrDebugData = (SwtmrDebugData *)LOS_MemAlloc(m_aucSysMem1, size);
106     if (g_swtmrDebugData == NULL) {
107         PRINT_ERR("SwtmrDebugDataInit malloc failed!\n");
108         return;
109     }
110     (VOID)memset_s(g_swtmrDebugData, size, 0, size);
111 #endif
112 }
113 
SwtmrDebugDataUpdate(SWTMR_CTRL_S * swtmr,UINT32 ticks,UINT32 times)114 STATIC INLINE VOID SwtmrDebugDataUpdate(SWTMR_CTRL_S *swtmr, UINT32 ticks, UINT32 times)
115 {
116 #ifdef LOSCFG_SWTMR_DEBUG
117     SwtmrDebugData *data = &g_swtmrDebugData[swtmr->usTimerID];
118     if (data->period != ticks) {
119         (VOID)memset_s(&data->base, sizeof(SwtmrDebugBase), 0, sizeof(SwtmrDebugBase));
120         data->period = ticks;
121     }
122     data->base.startTime = swtmr->startTime;
123     data->base.times += times;
124 #endif
125 }
126 
SwtmrDebugDataStart(SWTMR_CTRL_S * swtmr,UINT16 cpuid)127 STATIC INLINE VOID SwtmrDebugDataStart(SWTMR_CTRL_S *swtmr, UINT16 cpuid)
128 {
129 #ifdef LOSCFG_SWTMR_DEBUG
130     SwtmrDebugData *data = &g_swtmrDebugData[swtmr->usTimerID];
131     data->swtmrUsed = TRUE;
132     data->handler = swtmr->pfnHandler;
133     data->cpuid = cpuid;
134 #endif
135 }
136 
SwtmrDebugWaitTimeCalculate(UINT32 swtmrID,SwtmrHandlerItemPtr swtmrHandler)137 STATIC INLINE VOID SwtmrDebugWaitTimeCalculate(UINT32 swtmrID, SwtmrHandlerItemPtr swtmrHandler)
138 {
139 #ifdef LOSCFG_SWTMR_DEBUG
140     SwtmrDebugBase *data = &g_swtmrDebugData[swtmrID].base;
141     swtmrHandler->swtmrID = swtmrID;
142     UINT64 currTime = OsGetCurrSchedTimeCycle();
143     UINT64 waitTime = currTime - data->startTime;
144     data->waitTime += waitTime;
145     if (waitTime > data->waitTimeMax) {
146         data->waitTimeMax = waitTime;
147     }
148     data->readyStartTime = currTime;
149     data->waitCount++;
150 #endif
151 }
152 
SwtmrDebugDataClear(UINT32 swtmrID)153 STATIC INLINE VOID SwtmrDebugDataClear(UINT32 swtmrID)
154 {
155 #ifdef LOSCFG_SWTMR_DEBUG
156     (VOID)memset_s(&g_swtmrDebugData[swtmrID], sizeof(SwtmrDebugData), 0, sizeof(SwtmrDebugData));
157 #endif
158 }
159 
SwtmrHandler(SwtmrHandlerItemPtr swtmrHandle)160 STATIC INLINE VOID SwtmrHandler(SwtmrHandlerItemPtr swtmrHandle)
161 {
162 #ifdef LOSCFG_SWTMR_DEBUG
163     UINT32 intSave;
164     SwtmrDebugBase *data = &g_swtmrDebugData[swtmrHandle->swtmrID].base;
165     UINT64 startTime = OsGetCurrSchedTimeCycle();
166 #endif
167     swtmrHandle->handler(swtmrHandle->arg);
168 #ifdef LOSCFG_SWTMR_DEBUG
169     UINT64 runTime = OsGetCurrSchedTimeCycle() - startTime;
170     SWTMR_LOCK(intSave);
171     data->runTime += runTime;
172     if (runTime > data->runTimeMax) {
173         data->runTimeMax = runTime;
174     }
175     runTime = startTime - data->readyStartTime;
176     data->readyTime += runTime;
177     if (runTime > data->readyTimeMax) {
178         data->readyTimeMax = runTime;
179     }
180     data->runCount++;
181     SWTMR_UNLOCK(intSave);
182 #endif
183 }
184 
SwtmrWake(SwtmrRunqueue * srq,UINT64 startTime,SortLinkList * sortList)185 STATIC INLINE VOID SwtmrWake(SwtmrRunqueue *srq, UINT64 startTime, SortLinkList *sortList)
186 {
187     UINT32 intSave;
188     SWTMR_CTRL_S *swtmr = LOS_DL_LIST_ENTRY(sortList, SWTMR_CTRL_S, stSortList);
189     SwtmrHandlerItemPtr swtmrHandler = (SwtmrHandlerItemPtr)LOS_MemboxAlloc(g_swtmrHandlerPool);
190     LOS_ASSERT(swtmrHandler != NULL);
191 
192     OsHookCall(LOS_HOOK_TYPE_SWTMR_EXPIRED, swtmr);
193 
194     SWTMR_LOCK(intSave);
195     swtmrHandler->handler = swtmr->pfnHandler;
196     swtmrHandler->arg = swtmr->uwArg;
197     LOS_ListTailInsert(&srq->swtmrHandlerQueue, &swtmrHandler->node);
198     SwtmrDebugWaitTimeCalculate(swtmr->usTimerID, swtmrHandler);
199 
200     if (swtmr->ucMode == LOS_SWTMR_MODE_ONCE) {
201         SwtmrDelete(swtmr);
202 
203         if (swtmr->usTimerID < (OS_SWTMR_MAX_TIMERID - LOSCFG_BASE_CORE_SWTMR_LIMIT)) {
204             swtmr->usTimerID += LOSCFG_BASE_CORE_SWTMR_LIMIT;
205         } else {
206             swtmr->usTimerID %= LOSCFG_BASE_CORE_SWTMR_LIMIT;
207         }
208     } else if (swtmr->ucMode == LOS_SWTMR_MODE_NO_SELFDELETE) {
209         swtmr->ucState = OS_SWTMR_STATUS_CREATED;
210     } else {
211         swtmr->uwOverrun++;
212         swtmr->startTime = startTime;
213         (VOID)SwtmrToStart(swtmr, ArchCurrCpuid());
214     }
215 
216     SWTMR_UNLOCK(intSave);
217 }
218 
ScanSwtmrTimeList(SwtmrRunqueue * srq)219 STATIC INLINE VOID ScanSwtmrTimeList(SwtmrRunqueue *srq)
220 {
221     UINT32 intSave;
222     SortLinkAttribute *swtmrSortLink = &srq->swtmrSortLink;
223     LOS_DL_LIST *listObject = &swtmrSortLink->sortLink;
224 
225     /*
226      * it needs to be carefully coped with, since the swtmr is in specific sortlink
227      * while other cores still has the chance to process it, like stop the timer.
228      */
229     LOS_SpinLockSave(&swtmrSortLink->spinLock, &intSave);
230 
231     if (LOS_ListEmpty(listObject)) {
232         LOS_SpinUnlockRestore(&swtmrSortLink->spinLock, intSave);
233         return;
234     }
235     SortLinkList *sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
236 
237     UINT64 currTime = OsGetCurrSchedTimeCycle();
238     while (sortList->responseTime <= currTime) {
239         sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
240         UINT64 startTime = GET_SORTLIST_VALUE(sortList);
241         OsDeleteNodeSortLink(swtmrSortLink, sortList);
242         LOS_SpinUnlockRestore(&swtmrSortLink->spinLock, intSave);
243 
244         SwtmrWake(srq, startTime, sortList);
245 
246         LOS_SpinLockSave(&swtmrSortLink->spinLock, &intSave);
247         if (LOS_ListEmpty(listObject)) {
248             break;
249         }
250 
251         sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode);
252     }
253 
254     LOS_SpinUnlockRestore(&swtmrSortLink->spinLock, intSave);
255     return;
256 }
257 
SwtmrTask(VOID)258 STATIC VOID SwtmrTask(VOID)
259 {
260     SwtmrHandlerItem swtmrHandle;
261     UINT32 intSave;
262     UINT64 waitTime;
263 
264     SwtmrRunqueue *srq = &g_swtmrRunqueue[ArchCurrCpuid()];
265     LOS_DL_LIST *head = &srq->swtmrHandlerQueue;
266     for (;;) {
267         waitTime = OsSortLinkGetNextExpireTime(OsGetCurrSchedTimeCycle(), &srq->swtmrSortLink);
268         if (waitTime != 0) {
269             SCHEDULER_LOCK(intSave);
270             srq->swtmrTask->ops->delay(srq->swtmrTask, waitTime);
271             OsHookCall(LOS_HOOK_TYPE_MOVEDTASKTODELAYEDLIST, srq->swtmrTask);
272             SCHEDULER_UNLOCK(intSave);
273         }
274 
275         ScanSwtmrTimeList(srq);
276 
277         while (!LOS_ListEmpty(head)) {
278             SwtmrHandlerItemPtr swtmrHandlePtr = LOS_DL_LIST_ENTRY(LOS_DL_LIST_FIRST(head), SwtmrHandlerItem, node);
279             LOS_ListDelete(&swtmrHandlePtr->node);
280 
281             (VOID)memcpy_s(&swtmrHandle, sizeof(SwtmrHandlerItem), swtmrHandlePtr, sizeof(SwtmrHandlerItem));
282             (VOID)LOS_MemboxFree(g_swtmrHandlerPool, swtmrHandlePtr);
283             SwtmrHandler(&swtmrHandle);
284         }
285     }
286 }
287 
SwtmrTaskCreate(UINT16 cpuid,UINT32 * swtmrTaskID)288 STATIC UINT32 SwtmrTaskCreate(UINT16 cpuid, UINT32 *swtmrTaskID)
289 {
290     UINT32 ret;
291     TSK_INIT_PARAM_S swtmrTask;
292 
293     (VOID)memset_s(&swtmrTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
294     swtmrTask.pfnTaskEntry = (TSK_ENTRY_FUNC)SwtmrTask;
295     swtmrTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
296     swtmrTask.pcName = "Swt_Task";
297     swtmrTask.usTaskPrio = 0;
298     swtmrTask.uwResved = LOS_TASK_STATUS_DETACHED;
299 #ifdef LOSCFG_KERNEL_SMP
300     swtmrTask.usCpuAffiMask   = CPUID_TO_AFFI_MASK(cpuid);
301 #endif
302     ret = LOS_TaskCreate(swtmrTaskID, &swtmrTask);
303     if (ret == LOS_OK) {
304         OS_TCB_FROM_TID(*swtmrTaskID)->taskStatus |= OS_TASK_FLAG_SYSTEM_TASK;
305     }
306 
307     return ret;
308 }
309 
OsSwtmrTaskIDGetByCpuid(UINT16 cpuid)310 UINT32 OsSwtmrTaskIDGetByCpuid(UINT16 cpuid)
311 {
312     return g_swtmrRunqueue[cpuid].swtmrTask->taskID;
313 }
314 
OsIsSwtmrTask(const LosTaskCB * taskCB)315 BOOL OsIsSwtmrTask(const LosTaskCB *taskCB)
316 {
317     if (taskCB->taskEntry == (TSK_ENTRY_FUNC)SwtmrTask) {
318         return TRUE;
319     }
320     return FALSE;
321 }
322 
OsSwtmrRecycle(UINT32 processID)323 LITE_OS_SEC_TEXT_INIT VOID OsSwtmrRecycle(UINT32 processID)
324 {
325     for (UINT16 index = 0; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++) {
326         if (g_swtmrCBArray[index].uwOwnerPid == processID) {
327             LOS_SwtmrDelete(index);
328         }
329     }
330 }
331 
SwtmrBaseInit(VOID)332 STATIC UINT32 SwtmrBaseInit(VOID)
333 {
334     UINT32 ret;
335     UINT32 size = sizeof(SWTMR_CTRL_S) * LOSCFG_BASE_CORE_SWTMR_LIMIT;
336     SWTMR_CTRL_S *swtmr = (SWTMR_CTRL_S *)LOS_MemAlloc(m_aucSysMem0, size); /* system resident resource */
337     if (swtmr == NULL) {
338         return LOS_ERRNO_SWTMR_NO_MEMORY;
339     }
340 
341     (VOID)memset_s(swtmr, size, 0, size);
342     g_swtmrCBArray = swtmr;
343     LOS_ListInit(&g_swtmrFreeList);
344     for (UINT16 index = 0; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++, swtmr++) {
345         swtmr->usTimerID = index;
346         LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode);
347     }
348 
349     size = LOS_MEMBOX_SIZE(sizeof(SwtmrHandlerItem), OS_SWTMR_HANDLE_QUEUE_SIZE);
350     g_swtmrHandlerPool = (UINT8 *)LOS_MemAlloc(m_aucSysMem1, size); /* system resident resource */
351     if (g_swtmrHandlerPool == NULL) {
352         return LOS_ERRNO_SWTMR_NO_MEMORY;
353     }
354 
355     ret = LOS_MemboxInit(g_swtmrHandlerPool, size, sizeof(SwtmrHandlerItem));
356     if (ret != LOS_OK) {
357         return LOS_ERRNO_SWTMR_HANDLER_POOL_NO_MEM;
358     }
359 
360     for (UINT16 index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {
361         SwtmrRunqueue *srq = &g_swtmrRunqueue[index];
362         /* The linked list of all cores must be initialized at core 0 startup for load balancing */
363         OsSortLinkInit(&srq->swtmrSortLink);
364         LOS_ListInit(&srq->swtmrHandlerQueue);
365         srq->swtmrTask = NULL;
366     }
367 
368     SwtmrDebugDataInit();
369 
370     return LOS_OK;
371 }
372 
OsSwtmrInit(VOID)373 LITE_OS_SEC_TEXT_INIT UINT32 OsSwtmrInit(VOID)
374 {
375     UINT32 ret;
376     UINT32 cpuid = ArchCurrCpuid();
377     UINT32 swtmrTaskID;
378 
379     if (cpuid == 0) {
380         ret = SwtmrBaseInit();
381         if (ret != LOS_OK) {
382             goto ERROR;
383         }
384     }
385 
386     ret = SwtmrTaskCreate(cpuid, &swtmrTaskID);
387     if (ret != LOS_OK) {
388         ret = LOS_ERRNO_SWTMR_TASK_CREATE_FAILED;
389         goto ERROR;
390     }
391 
392     SwtmrRunqueue *srq = &g_swtmrRunqueue[cpuid];
393     srq->swtmrTask = OsGetTaskCB(swtmrTaskID);
394     return LOS_OK;
395 
396 ERROR:
397     PRINT_ERR("OsSwtmrInit error! ret = %u\n", ret);
398     (VOID)LOS_MemFree(m_aucSysMem0, g_swtmrCBArray);
399     g_swtmrCBArray = NULL;
400     (VOID)LOS_MemFree(m_aucSysMem1, g_swtmrHandlerPool);
401     g_swtmrHandlerPool = NULL;
402     return ret;
403 }
404 
405 #ifdef LOSCFG_KERNEL_SMP
FindIdleSwtmrRunqueue(UINT16 * idleCpuid)406 STATIC INLINE VOID FindIdleSwtmrRunqueue(UINT16 *idleCpuid)
407 {
408     SwtmrRunqueue *idleRq = &g_swtmrRunqueue[0];
409     UINT32 nodeNum = OsGetSortLinkNodeNum(&idleRq->swtmrSortLink);
410     UINT16 cpuid = 1;
411     do {
412         SwtmrRunqueue *srq = &g_swtmrRunqueue[cpuid];
413         UINT32 temp = OsGetSortLinkNodeNum(&srq->swtmrSortLink);
414         if (nodeNum > temp) {
415             *idleCpuid = cpuid;
416             nodeNum = temp;
417         }
418         cpuid++;
419     } while (cpuid < LOSCFG_KERNEL_CORE_NUM);
420 }
421 #endif
422 
AddSwtmr2TimeList(SortLinkList * node,UINT64 responseTime,UINT16 cpuid)423 STATIC INLINE VOID AddSwtmr2TimeList(SortLinkList *node, UINT64 responseTime, UINT16 cpuid)
424 {
425     SwtmrRunqueue *srq = &g_swtmrRunqueue[cpuid];
426     OsAdd2SortLink(&srq->swtmrSortLink, node, responseTime, cpuid);
427 }
428 
DeSwtmrFromTimeList(SortLinkList * node)429 STATIC INLINE VOID DeSwtmrFromTimeList(SortLinkList *node)
430 {
431 #ifdef LOSCFG_KERNEL_SMP
432     UINT16 cpuid = OsGetSortLinkNodeCpuid(node);
433 #else
434     UINT16 cpuid = 0;
435 #endif
436     SwtmrRunqueue *srq = &g_swtmrRunqueue[cpuid];
437     OsDeleteFromSortLink(&srq->swtmrSortLink, node);
438     return;
439 }
440 
SwtmrAdjustCheck(UINT16 cpuid,UINT64 responseTime)441 STATIC VOID SwtmrAdjustCheck(UINT16 cpuid, UINT64 responseTime)
442 {
443     UINT32 ret;
444     UINT32 intSave;
445     SwtmrRunqueue *srq = &g_swtmrRunqueue[cpuid];
446     SCHEDULER_LOCK(intSave);
447     if ((srq->swtmrTask == NULL) || !OsTaskIsBlocked(srq->swtmrTask)) {
448         SCHEDULER_UNLOCK(intSave);
449         return;
450     }
451 
452     if (responseTime >= GET_SORTLIST_VALUE(&srq->swtmrTask->sortList)) {
453         SCHEDULER_UNLOCK(intSave);
454         return;
455     }
456 
457     ret = OsSchedTimeoutQueueAdjust(srq->swtmrTask, responseTime);
458     SCHEDULER_UNLOCK(intSave);
459     if (ret != LOS_OK) {
460         return;
461     }
462 
463     if (cpuid == ArchCurrCpuid()) {
464         OsSchedExpireTimeUpdate();
465     } else {
466         LOS_MpSchedule(CPUID_TO_AFFI_MASK(cpuid));
467     }
468 }
469 
SwtmrToStart(SWTMR_CTRL_S * swtmr,UINT16 cpuid)470 STATIC UINT64 SwtmrToStart(SWTMR_CTRL_S *swtmr, UINT16 cpuid)
471 {
472     UINT32 ticks;
473     UINT32 times = 0;
474 
475     if ((swtmr->uwOverrun == 0) && ((swtmr->ucMode == LOS_SWTMR_MODE_ONCE) ||
476         (swtmr->ucMode == LOS_SWTMR_MODE_OPP) ||
477         (swtmr->ucMode == LOS_SWTMR_MODE_NO_SELFDELETE))) {
478         ticks = swtmr->uwExpiry;
479     } else {
480         ticks = swtmr->uwInterval;
481     }
482     swtmr->ucState = OS_SWTMR_STATUS_TICKING;
483 
484     UINT64 period = (UINT64)ticks * OS_CYCLE_PER_TICK;
485     UINT64 responseTime = swtmr->startTime + period;
486     UINT64 currTime = OsGetCurrSchedTimeCycle();
487     if (responseTime < currTime) {
488         times = (UINT32)((currTime - swtmr->startTime) / period);
489         swtmr->startTime += times * period;
490         responseTime = swtmr->startTime + period;
491         PRINT_WARN("Swtmr already timeout! SwtmrID: %u\n", swtmr->usTimerID);
492     }
493 
494     AddSwtmr2TimeList(&swtmr->stSortList, responseTime, cpuid);
495     SwtmrDebugDataUpdate(swtmr, ticks, times);
496     return responseTime;
497 }
498 
499 /*
500  * Description: Start Software Timer
501  * Input      : swtmr --- Need to start software timer
502  */
SwtmrStart(SWTMR_CTRL_S * swtmr)503 STATIC INLINE VOID SwtmrStart(SWTMR_CTRL_S *swtmr)
504 {
505     UINT64 responseTime;
506     UINT16 idleCpu = 0;
507 #ifdef LOSCFG_KERNEL_SMP
508     FindIdleSwtmrRunqueue(&idleCpu);
509 #endif
510     swtmr->startTime = OsGetCurrSchedTimeCycle();
511     responseTime = SwtmrToStart(swtmr, idleCpu);
512 
513     SwtmrDebugDataStart(swtmr, idleCpu);
514 
515     SwtmrAdjustCheck(idleCpu, responseTime);
516 }
517 
518 /*
519  * Description: Delete Software Timer
520  * Input      : swtmr --- Need to delete software timer, When using, Ensure that it can't be NULL.
521  */
SwtmrDelete(SWTMR_CTRL_S * swtmr)522 STATIC INLINE VOID SwtmrDelete(SWTMR_CTRL_S *swtmr)
523 {
524     /* insert to free list */
525     LOS_ListTailInsert(&g_swtmrFreeList, &swtmr->stSortList.sortLinkNode);
526     swtmr->ucState = OS_SWTMR_STATUS_UNUSED;
527     swtmr->uwOwnerPid = 0;
528 
529     SwtmrDebugDataClear(swtmr->usTimerID);
530 }
531 
SwtmrRestart(UINT64 startTime,SortLinkList * sortList,UINT16 cpuid)532 STATIC INLINE VOID SwtmrRestart(UINT64 startTime, SortLinkList *sortList, UINT16 cpuid)
533 {
534     UINT32 intSave;
535 
536     SWTMR_CTRL_S *swtmr = LOS_DL_LIST_ENTRY(sortList, SWTMR_CTRL_S, stSortList);
537     SWTMR_LOCK(intSave);
538     swtmr->startTime = startTime;
539     (VOID)SwtmrToStart(swtmr, cpuid);
540     SWTMR_UNLOCK(intSave);
541 }
542 
OsSwtmrResponseTimeReset(UINT64 startTime)543 VOID OsSwtmrResponseTimeReset(UINT64 startTime)
544 {
545     UINT16 cpuid = ArchCurrCpuid();
546     SortLinkAttribute *swtmrSortLink = &g_swtmrRunqueue[cpuid].swtmrSortLink;
547     LOS_DL_LIST *listHead = &swtmrSortLink->sortLink;
548     LOS_DL_LIST *listNext = listHead->pstNext;
549 
550     LOS_SpinLock(&swtmrSortLink->spinLock);
551     while (listNext != listHead) {
552         SortLinkList *sortList = LOS_DL_LIST_ENTRY(listNext, SortLinkList, sortLinkNode);
553         OsDeleteNodeSortLink(swtmrSortLink, sortList);
554         LOS_SpinUnlock(&swtmrSortLink->spinLock);
555 
556         SwtmrRestart(startTime, sortList, cpuid);
557 
558         LOS_SpinLock(&swtmrSortLink->spinLock);
559         listNext = listNext->pstNext;
560     }
561     LOS_SpinUnlock(&swtmrSortLink->spinLock);
562 }
563 
SwtmrRunqueueFind(SortLinkAttribute * swtmrSortLink,SCHED_TL_FIND_FUNC checkFunc,UINTPTR arg)564 STATIC INLINE BOOL SwtmrRunqueueFind(SortLinkAttribute *swtmrSortLink, SCHED_TL_FIND_FUNC checkFunc, UINTPTR arg)
565 {
566     LOS_DL_LIST *listObject = &swtmrSortLink->sortLink;
567     LOS_DL_LIST *list = listObject->pstNext;
568 
569     LOS_SpinLock(&swtmrSortLink->spinLock);
570     while (list != listObject) {
571         SortLinkList *listSorted = LOS_DL_LIST_ENTRY(list, SortLinkList, sortLinkNode);
572         if (checkFunc((UINTPTR)listSorted, arg)) {
573             LOS_SpinUnlock(&swtmrSortLink->spinLock);
574             return TRUE;
575         }
576         list = list->pstNext;
577     }
578 
579     LOS_SpinUnlock(&swtmrSortLink->spinLock);
580     return FALSE;
581 }
582 
SwtmrTimeListFind(SCHED_TL_FIND_FUNC checkFunc,UINTPTR arg)583 STATIC BOOL SwtmrTimeListFind(SCHED_TL_FIND_FUNC checkFunc, UINTPTR arg)
584 {
585     for (UINT16 cpuid = 0; cpuid < LOSCFG_KERNEL_CORE_NUM; cpuid++) {
586         SortLinkAttribute *swtmrSortLink = &g_swtmrRunqueue[cpuid].swtmrSortLink;
587         if (SwtmrRunqueueFind(swtmrSortLink, checkFunc, arg)) {
588             return TRUE;
589         }
590     }
591     return FALSE;
592 }
593 
OsSwtmrWorkQueueFind(SCHED_TL_FIND_FUNC checkFunc,UINTPTR arg)594 BOOL OsSwtmrWorkQueueFind(SCHED_TL_FIND_FUNC checkFunc, UINTPTR arg)
595 {
596     UINT32 intSave;
597 
598     SWTMR_LOCK(intSave);
599     BOOL find = SwtmrTimeListFind(checkFunc, arg);
600     SWTMR_UNLOCK(intSave);
601     return find;
602 }
603 
604 /*
605  * Description: Get next timeout
606  * Return     : Count of the Timer list
607  */
OsSwtmrGetNextTimeout(VOID)608 LITE_OS_SEC_TEXT UINT32 OsSwtmrGetNextTimeout(VOID)
609 {
610     UINT64 currTime = OsGetCurrSchedTimeCycle();
611     SwtmrRunqueue *srq = &g_swtmrRunqueue[ArchCurrCpuid()];
612     UINT64 time = (OsSortLinkGetNextExpireTime(currTime, &srq->swtmrSortLink) / OS_CYCLE_PER_TICK);
613     if (time > OS_INVALID_VALUE) {
614         time = OS_INVALID_VALUE;
615     }
616     return (UINT32)time;
617 }
618 
619 /*
620  * Description: Stop of Software Timer interface
621  * Input      : swtmr --- the software timer control handler
622  */
SwtmrStop(SWTMR_CTRL_S * swtmr)623 STATIC VOID SwtmrStop(SWTMR_CTRL_S *swtmr)
624 {
625     swtmr->ucState = OS_SWTMR_STATUS_CREATED;
626     swtmr->uwOverrun = 0;
627 
628     DeSwtmrFromTimeList(&swtmr->stSortList);
629 }
630 
631 /*
632  * Description: Get next software timer expiretime
633  * Input      : swtmr --- the software timer control handler
634  */
OsSwtmrTimeGet(const SWTMR_CTRL_S * swtmr)635 LITE_OS_SEC_TEXT STATIC UINT32 OsSwtmrTimeGet(const SWTMR_CTRL_S *swtmr)
636 {
637     UINT64 currTime = OsGetCurrSchedTimeCycle();
638     UINT64 time = (OsSortLinkGetTargetExpireTime(currTime, &swtmr->stSortList) / OS_CYCLE_PER_TICK);
639     if (time > OS_INVALID_VALUE) {
640         time = OS_INVALID_VALUE;
641     }
642     return (UINT32)time;
643 }
644 
LOS_SwtmrCreate(UINT32 interval,UINT8 mode,SWTMR_PROC_FUNC handler,UINT16 * swtmrID,UINTPTR arg)645 LITE_OS_SEC_TEXT_INIT UINT32 LOS_SwtmrCreate(UINT32 interval,
646                                              UINT8 mode,
647                                              SWTMR_PROC_FUNC handler,
648                                              UINT16 *swtmrID,
649                                              UINTPTR arg)
650 {
651     SWTMR_CTRL_S *swtmr = NULL;
652     UINT32 intSave;
653     SortLinkList *sortList = NULL;
654 
655     if (interval == 0) {
656         return LOS_ERRNO_SWTMR_INTERVAL_NOT_SUITED;
657     }
658 
659     if ((mode != LOS_SWTMR_MODE_ONCE) && (mode != LOS_SWTMR_MODE_PERIOD) &&
660         (mode != LOS_SWTMR_MODE_NO_SELFDELETE)) {
661         return LOS_ERRNO_SWTMR_MODE_INVALID;
662     }
663 
664     if (handler == NULL) {
665         return LOS_ERRNO_SWTMR_PTR_NULL;
666     }
667 
668     if (swtmrID == NULL) {
669         return LOS_ERRNO_SWTMR_RET_PTR_NULL;
670     }
671 
672     SWTMR_LOCK(intSave);
673     if (LOS_ListEmpty(&g_swtmrFreeList)) {
674         SWTMR_UNLOCK(intSave);
675         return LOS_ERRNO_SWTMR_MAXSIZE;
676     }
677 
678     sortList = LOS_DL_LIST_ENTRY(g_swtmrFreeList.pstNext, SortLinkList, sortLinkNode);
679     swtmr = LOS_DL_LIST_ENTRY(sortList, SWTMR_CTRL_S, stSortList);
680     LOS_ListDelete(LOS_DL_LIST_FIRST(&g_swtmrFreeList));
681     SWTMR_UNLOCK(intSave);
682 
683     swtmr->uwOwnerPid = OsCurrProcessGet()->processID;
684     swtmr->pfnHandler = handler;
685     swtmr->ucMode = mode;
686     swtmr->uwOverrun = 0;
687     swtmr->uwInterval = interval;
688     swtmr->uwExpiry = interval;
689     swtmr->uwArg = arg;
690     swtmr->ucState = OS_SWTMR_STATUS_CREATED;
691     SET_SORTLIST_VALUE(&swtmr->stSortList, OS_SORT_LINK_INVALID_TIME);
692     *swtmrID = swtmr->usTimerID;
693     OsHookCall(LOS_HOOK_TYPE_SWTMR_CREATE, swtmr);
694     return LOS_OK;
695 }
696 
LOS_SwtmrStart(UINT16 swtmrID)697 LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStart(UINT16 swtmrID)
698 {
699     SWTMR_CTRL_S *swtmr = NULL;
700     UINT32 intSave;
701     UINT32 ret = LOS_OK;
702     UINT16 swtmrCBID;
703 
704     if (swtmrID >= OS_SWTMR_MAX_TIMERID) {
705         return LOS_ERRNO_SWTMR_ID_INVALID;
706     }
707 
708     swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;
709     swtmr = g_swtmrCBArray + swtmrCBID;
710 
711     SWTMR_LOCK(intSave);
712     if (swtmr->usTimerID != swtmrID) {
713         SWTMR_UNLOCK(intSave);
714         return LOS_ERRNO_SWTMR_ID_INVALID;
715     }
716 
717     switch (swtmr->ucState) {
718         case OS_SWTMR_STATUS_UNUSED:
719             ret = LOS_ERRNO_SWTMR_NOT_CREATED;
720             break;
721         /*
722          * If the status of swtmr is timing, it should stop the swtmr first,
723          * then start the swtmr again.
724          */
725         case OS_SWTMR_STATUS_TICKING:
726             SwtmrStop(swtmr);
727             /* fall-through */
728         case OS_SWTMR_STATUS_CREATED:
729             SwtmrStart(swtmr);
730             break;
731         default:
732             ret = LOS_ERRNO_SWTMR_STATUS_INVALID;
733             break;
734     }
735 
736     SWTMR_UNLOCK(intSave);
737     OsHookCall(LOS_HOOK_TYPE_SWTMR_START, swtmr);
738     return ret;
739 }
740 
LOS_SwtmrStop(UINT16 swtmrID)741 LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStop(UINT16 swtmrID)
742 {
743     SWTMR_CTRL_S *swtmr = NULL;
744     UINT32 intSave;
745     UINT32 ret = LOS_OK;
746     UINT16 swtmrCBID;
747 
748     if (swtmrID >= OS_SWTMR_MAX_TIMERID) {
749         return LOS_ERRNO_SWTMR_ID_INVALID;
750     }
751 
752     swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;
753     swtmr = g_swtmrCBArray + swtmrCBID;
754     SWTMR_LOCK(intSave);
755 
756     if (swtmr->usTimerID != swtmrID) {
757         SWTMR_UNLOCK(intSave);
758         return LOS_ERRNO_SWTMR_ID_INVALID;
759     }
760 
761     switch (swtmr->ucState) {
762         case OS_SWTMR_STATUS_UNUSED:
763             ret = LOS_ERRNO_SWTMR_NOT_CREATED;
764             break;
765         case OS_SWTMR_STATUS_CREATED:
766             ret = LOS_ERRNO_SWTMR_NOT_STARTED;
767             break;
768         case OS_SWTMR_STATUS_TICKING:
769             SwtmrStop(swtmr);
770             break;
771         default:
772             ret = LOS_ERRNO_SWTMR_STATUS_INVALID;
773             break;
774     }
775 
776     SWTMR_UNLOCK(intSave);
777     OsHookCall(LOS_HOOK_TYPE_SWTMR_STOP, swtmr);
778     return ret;
779 }
780 
LOS_SwtmrTimeGet(UINT16 swtmrID,UINT32 * tick)781 LITE_OS_SEC_TEXT UINT32 LOS_SwtmrTimeGet(UINT16 swtmrID, UINT32 *tick)
782 {
783     SWTMR_CTRL_S *swtmr = NULL;
784     UINT32 intSave;
785     UINT32 ret = LOS_OK;
786     UINT16 swtmrCBID;
787 
788     if (swtmrID >= OS_SWTMR_MAX_TIMERID) {
789         return LOS_ERRNO_SWTMR_ID_INVALID;
790     }
791 
792     if (tick == NULL) {
793         return LOS_ERRNO_SWTMR_TICK_PTR_NULL;
794     }
795 
796     swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;
797     swtmr = g_swtmrCBArray + swtmrCBID;
798     SWTMR_LOCK(intSave);
799 
800     if (swtmr->usTimerID != swtmrID) {
801         SWTMR_UNLOCK(intSave);
802         return LOS_ERRNO_SWTMR_ID_INVALID;
803     }
804     switch (swtmr->ucState) {
805         case OS_SWTMR_STATUS_UNUSED:
806             ret = LOS_ERRNO_SWTMR_NOT_CREATED;
807             break;
808         case OS_SWTMR_STATUS_CREATED:
809             ret = LOS_ERRNO_SWTMR_NOT_STARTED;
810             break;
811         case OS_SWTMR_STATUS_TICKING:
812             *tick = OsSwtmrTimeGet(swtmr);
813             break;
814         default:
815             ret = LOS_ERRNO_SWTMR_STATUS_INVALID;
816             break;
817     }
818     SWTMR_UNLOCK(intSave);
819     return ret;
820 }
821 
LOS_SwtmrDelete(UINT16 swtmrID)822 LITE_OS_SEC_TEXT UINT32 LOS_SwtmrDelete(UINT16 swtmrID)
823 {
824     SWTMR_CTRL_S *swtmr = NULL;
825     UINT32 intSave;
826     UINT32 ret = LOS_OK;
827     UINT16 swtmrCBID;
828 
829     if (swtmrID >= OS_SWTMR_MAX_TIMERID) {
830         return LOS_ERRNO_SWTMR_ID_INVALID;
831     }
832 
833     swtmrCBID = swtmrID % LOSCFG_BASE_CORE_SWTMR_LIMIT;
834     swtmr = g_swtmrCBArray + swtmrCBID;
835     SWTMR_LOCK(intSave);
836 
837     if (swtmr->usTimerID != swtmrID) {
838         SWTMR_UNLOCK(intSave);
839         return LOS_ERRNO_SWTMR_ID_INVALID;
840     }
841 
842     switch (swtmr->ucState) {
843         case OS_SWTMR_STATUS_UNUSED:
844             ret = LOS_ERRNO_SWTMR_NOT_CREATED;
845             break;
846         case OS_SWTMR_STATUS_TICKING:
847             SwtmrStop(swtmr);
848             /* fall-through */
849         case OS_SWTMR_STATUS_CREATED:
850             SwtmrDelete(swtmr);
851             break;
852         default:
853             ret = LOS_ERRNO_SWTMR_STATUS_INVALID;
854             break;
855     }
856 
857     SWTMR_UNLOCK(intSave);
858     OsHookCall(LOS_HOOK_TYPE_SWTMR_DELETE, swtmr);
859     return ret;
860 }
861 
862 #endif /* LOSCFG_BASE_CORE_SWTMR_ENABLE */
863