精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

鴻蒙輕內核M核源碼分析系列九 軟件定時器Swtmr

系統
本文帶領大家一起剖析鴻蒙輕內核的定時器模塊的源代碼,包含定時器的結構體、定時器池初始化、定時器創建、刪除、啟動停止等。

[[401679]]

想了解更多內容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術社區

https://harmonyos.51cto.com

軟件定時器(Software Timer)是基于系統Tick時鐘中斷且由軟件來模擬的定時器。當經過設定的Tick數后,會觸發用戶自定義的回調函數。硬件定時器受硬件的限制,數量上不足以滿足用戶的實際需求。鴻蒙輕內核提供了軟件定時器功能可以提供更多的定時器,滿足用戶需求。

本文通過分析鴻蒙輕內核定時器模塊的源碼,掌握定時器使用上的差異。

接下來,我們看下定時器的結構體,定時器初始化,定時器常用操作的源代碼。

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。其他結構體成員的解釋見注釋部分。

  1. typedef struct tagSwTmrCtrl { 
  2.     struct tagSwTmrCtrl *pstNext;       /* 指向下一個定時器結構體的指針       */ 
  3.     UINT8               ucState;        /* 定時器狀態,取值枚舉SwtmrState    */ 
  4.     UINT8               ucMode;         /* 定時器模式,取值枚舉enSwTmrType   */ 
  5. #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1) 
  6.     UINT8               ucRouses;       /* 喚醒開關                         */ 
  7.     UINT8               ucSensitive;    /* 對齊開關                         */ 
  8. #endif 
  9.     UINT32              usTimerID;      /* 定時器編號Id                     */ 
  10.     UINT32              uwCount;        /* 定時器運行的次數                  */ 
  11.     UINT32              uwInterval;     /* 周期定時器超時間隔 (單位: tick)   */ 
  12.     UINT32              uwArg;          /* 定時器超時回調函數參數            */ 
  13.     SWTMR_PROC_FUNC     pfnHandler;     /* 定時器超時回調函數                */ 
  14.     SortLinkList        stSortList;     /* 定時器排序鏈表                    */ 
  15. } SWTMR_CTRL_S; 

另外,還對回調函數及其參數單獨定義了一個結構體SwtmrHandlerItem,如下:

  1. typedef struct { 
  2.     SWTMR_PROC_FUNC handler;    /**< 定時器超時回調函數    */ 
  3.     UINTPTR arg;                /**< 定時器超時回調函數參數 */ 
  4. } SwtmrHandlerItem; 

1.2 定時器常用宏定義

定時器頭文件kernel\include\los_swtmr.h中還提供了相關的枚舉和宏,從定時器池里獲取定時器控制塊的宏定義OS_SWT_FROM_SID如下:

  1. #define OS_SWT_FROM_SID(swtmrId)    ((SWTMR_CTRL_S *)g_swtmrCBArray + ((swtmrId) % LOSCFG_BASE_CORE_SWTMR_LIMIT)) 

頭文件中定義的定時器幾個枚舉如下:

  1. enum SwtmrState { 
  2.     OS_SWTMR_STATUS_UNUSED,     /**< 定時器未使用    */ 
  3.     OS_SWTMR_STATUS_CREATED,    /**< 定時器已創建     */ 
  4.     OS_SWTMR_STATUS_TICKING     /**< 定時器計時中     */ 
  5. }; 
  6.  
  7. #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1) 
  8.  
  9. enum enSwTmrRousesType { 
  10.     OS_SWTMR_ROUSES_IGNORE, /* 定時器不能喚醒系統 */ 
  11.     OS_SWTMR_ROUSES_ALLOW,  /* 定時器能喚醒系統 */ 
  12. }; 
  13.  
  14. enum enSwTmrAlignSensitive { 
  15.     OS_SWTMR_ALIGN_SENSITIVE,   /* 定時器不需要對齊 */ 
  16.     OS_SWTMR_ALIGN_INSENSITIVE, /* 定時器需要對齊 */ 
  17. }; 
  18. #endif 
  19.  
  20. enum EnSwTmrType { 
  21.     LOS_SWTMR_MODE_ONCE,            /* 一次性定時器, 值為0. */ 
  22.     LOS_SWTMR_MODE_PERIOD,          /* 周期定時器,值為 1. */ 
  23.     LOS_SWTMR_MODE_NO_SELFDELETE,   /* 一次性定時器,不會自刪除,值為2 */ 
  24.     LOS_SWTMR_MODE_OPP,             /* 一次性定時器完成后,使能周期性定時器。該模式暫不支持。值為3 */ 
  25. }; 

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。

  1. LITE_OS_SEC_TEXT_INIT UINT32 OsSwtmrInit(VOID) 
  2.     UINT32 size
  3.     UINT16 index
  4.     UINT32 ret; 
  5.  
  6. #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1) 
  7.     // Ignore the return code when matching CSEC rule 6.6(1). 
  8. ⑴  (VOID)memset_s((VOID *)g_swtmrAlignID, sizeof(SwtmrAlignData) * LOSCFG_BASE_CORE_SWTMR_LIMIT, 
  9.                    0, sizeof(SwtmrAlignData) * LOSCFG_BASE_CORE_SWTMR_LIMIT); 
  10. #endif 
  11.  
  12. ⑵  size = sizeof(SWTMR_CTRL_S) * LOSCFG_BASE_CORE_SWTMR_LIMIT; 
  13.     SWTMR_CTRL_S *swtmr = (SWTMR_CTRL_S *)LOS_MemAlloc(m_aucSysMem0, size); 
  14.     if (swtmr == NULL) { 
  15.         return LOS_ERRNO_SWTMR_NO_MEMORY; 
  16.     } 
  17.     // Ignore the return code when matching CSEC rule 6.6(3). 
  18.     (VOID)memset_s((VOID *)swtmr, size, 0, size); 
  19.     g_swtmrCBArray = swtmr; 
  20. ⑶  g_swtmrFreeList = swtmr; 
  21.     swtmr->usTimerID = 0; 
  22.     SWTMR_CTRL_S *temp = swtmr; 
  23.     swtmr++; 
  24.     for (index = 1; index < LOSCFG_BASE_CORE_SWTMR_LIMIT; index++, swtmr++) { 
  25.         swtmr->usTimerID = index
  26.         temp->pstNext = swtmr; 
  27.         temp = swtmr; 
  28.     } 
  29.  
  30. ⑷  ret = LOS_QueueCreate((CHAR *)NULL, OS_SWTMR_HANDLE_QUEUE_SIZE, 
  31.                           &g_swtmrHandlerQueue, 0, sizeof(SwtmrHandlerItem)); 
  32.     if (ret != LOS_OK) { 
  33.         (VOID)LOS_MemFree(m_aucSysMem0, swtmr); 
  34.         return LOS_ERRNO_SWTMR_QUEUE_CREATE_FAILED; 
  35.     } 
  36.  
  37. ⑸  ret = OsSwtmrTaskCreate(); 
  38.     if (ret != LOS_OK) { 
  39.         (VOID)LOS_MemFree(m_aucSysMem0, swtmr); 
  40.         return LOS_ERRNO_SWTMR_TASK_CREATE_FAILED; 
  41.     } 
  42.  
  43. ⑹  g_swtmrSortLinkList = OsGetSortLinkAttribute(OS_SORT_LINK_SWTMR); 
  44.     if (g_swtmrSortLinkList == NULL) { 
  45.         (VOID)LOS_MemFree(m_aucSysMem0, swtmr); 
  46.         return LOS_NOK; 
  47.     } 
  48.  
  49.     ret = OsSortLinkInit(g_swtmrSortLinkList); 
  50.     if (ret != LOS_OK) { 
  51.         (VOID)LOS_MemFree(m_aucSysMem0, swtmr); 
  52.         return LOS_NOK; 
  53.     } 
  54.  
  55. ⑺  ret = OsSchedSwtmrScanRegister((SchedScan)OsSwtmrScan); 
  56.     if (ret != LOS_OK) { 
  57.         (VOID)LOS_MemFree(m_aucSysMem0, swtmr); 
  58.         return LOS_NOK; 
  59.     } 
  60.  
  61.     return LOS_OK; 

我們再看一下定時器任務的入口函數為OsSwtmrTask()。

⑴進行for永久循環,隊列讀取不到數據時會阻塞,因為優先級比較高,定時器隊列有數據時該任務就會執行。從定時器隊列中讀取定時器處理函數地址放入指針地址&swtmrHandle,讀取的長度為sizeof(SwtmrHandlerItem)。成功讀取后,獲取定時器回調函數及其參數,然后

⑵處執行定時器回調函數。記錄定時器回調函數的執行時間,

⑶處判斷執行時間是否超時,如果超時,打印警告信息。

  1. LITE_OS_SEC_TEXT VOID OsSwtmrTask(VOID) 
  2.     SwtmrHandlerItem swtmrHandle; 
  3.     UINT32 readSize; 
  4.     UINT32 ret; 
  5.     UINT64 tick; 
  6.     readSize = sizeof(SwtmrHandlerItem); 
  7.  
  8.     for (;;) { 
  9. ⑴      ret = LOS_QueueReadCopy(g_swtmrHandlerQueue, &swtmrHandle, &readSize, LOS_WAIT_FOREVER); 
  10.         if ((ret == LOS_OK) && (readSize == sizeof(SwtmrHandlerItem))) { 
  11.             if (swtmrHandle.handler == NULL) { 
  12.                 continue
  13.             } 
  14.  
  15.             tick = LOS_TickCountGet(); 
  16. ⑵          swtmrHandle.handler(swtmrHandle.arg); 
  17.             tick = LOS_TickCountGet() - tick; 
  18.  
  19. ⑶          if (tick >= SWTMR_MAX_RUNNING_TICKS) { 
  20.                 PRINT_WARN("timer_handler(%p) cost too many ms(%d)\n"
  21.                            swtmrHandle.handler, 
  22.                            (UINT32)((tick * OS_SYS_MS_PER_SECOND) / LOSCFG_BASE_CORE_TICK_PER_SECOND)); 
  23.             } 
  24.         } 
  25.     } 

3、定時器常用操作

3.1 定時器創建

我們分析下創建定時器函數LOS_SwtmrCreate()的代碼。先不考慮定時器對齊LOSCFG_BASE_CORE_SWTMR_ALIGN的情況。先看下函數參數,interval是定時器執行時間間隔,mode是創建的定時器模式,handler、arg是定時器回調函數及其參數。swtmrId是定時器編號。

⑴處對傳入參數定時器超時間隔、定時器模式、回調函數,定時器編號進行校驗。

⑵判斷空閑定時器池是否為空,為空則返回錯誤,無法創建定時器。

⑶處如果定時器不為空,則獲取定時器控制塊swtmr。⑷處對定時器控制塊信息進行初始化。

⑸處把該定時器排序鏈表節點的響應時間responseTime初始化為-1。

  1. #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1) 
  2. LITE_OS_SEC_TEXT_INIT UINT32 LOS_SwtmrCreate(UINT32 interval, 
  3.                                              UINT8 mode, 
  4.                                              SWTMR_PROC_FUNC handler, 
  5.                                              UINT32 *swtmrId, 
  6.                                              UINT32 arg, 
  7.                                              UINT8 rouses, 
  8.                                              UINT8 sensitive) 
  9. #else 
  10. LITE_OS_SEC_TEXT_INIT UINT32 LOS_SwtmrCreate(UINT32 interval, 
  11.                                              UINT8 mode, 
  12.                                              SWTMR_PROC_FUNC handler, 
  13.                                              UINT32 *swtmrId, 
  14.                                              UINT32 arg) 
  15. #endif 
  16.     SWTMR_CTRL_S  *swtmr = NULL
  17.     UINT32 intSave; 
  18.  
  19. ⑴  if (interval == 0) { 
  20.         return LOS_ERRNO_SWTMR_INTERVAL_NOT_SUITED; 
  21.     } 
  22.  
  23.     if ((mode != LOS_SWTMR_MODE_ONCE) && 
  24.         (mode != LOS_SWTMR_MODE_PERIOD) && 
  25.         (mode != LOS_SWTMR_MODE_NO_SELFDELETE)) { 
  26.         return LOS_ERRNO_SWTMR_MODE_INVALID; 
  27.     } 
  28.  
  29.     if (handler == NULL) { 
  30.         return LOS_ERRNO_SWTMR_PTR_NULL; 
  31.     } 
  32.  
  33.     if (swtmrId == NULL) { 
  34.         return LOS_ERRNO_SWTMR_RET_PTR_NULL; 
  35.     } 
  36.  
  37. #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1) 
  38.     if ((rouses != OS_SWTMR_ROUSES_IGNORE) && (rouses != OS_SWTMR_ROUSES_ALLOW)) { 
  39.         return OS_ERRNO_SWTMR_ROUSES_INVALID; 
  40.     } 
  41.  
  42.     if ((sensitive != OS_SWTMR_ALIGN_INSENSITIVE) && (sensitive != OS_SWTMR_ALIGN_SENSITIVE)) { 
  43.         return OS_ERRNO_SWTMR_ALIGN_INVALID; 
  44.     } 
  45. #endif 
  46.  
  47.     intSave = LOS_IntLock(); 
  48. ⑵  if (g_swtmrFreeList == NULL) { 
  49.         LOS_IntRestore(intSave); 
  50.         return LOS_ERRNO_SWTMR_MAXSIZE; 
  51.     } 
  52.  
  53. ⑶  swtmr = g_swtmrFreeList; 
  54.     g_swtmrFreeList = swtmr->pstNext; 
  55.     LOS_IntRestore(intSave); 
  56. ⑷  swtmr->pfnHandler    = handler; 
  57.     swtmr->ucMode        = mode; 
  58.     swtmr->uwInterval    = interval; 
  59.     swtmr->pstNext       = (SWTMR_CTRL_S *)NULL
  60.     swtmr->uwCount       = 0; 
  61.     swtmr->uwArg         = arg; 
  62. #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1) 
  63.     swtmr->ucRouses      = rouses; 
  64.     swtmr->ucSensitive   = sensitive; 
  65. #endif 
  66.     swtmr->ucState       = OS_SWTMR_STATUS_CREATED; 
  67.     *swtmrId = swtmr->usTimerID; 
  68. ⑸  SET_SORTLIST_VALUE(&swtmr->stSortList, OS_SORT_LINK_INVALID_TIME); 
  69.  
  70.     return LOS_OK; 

3.2 定時器刪除

我們可以使用函數LOS_SwtmrDelete(UINT32 swtmrId)來刪除定時器,下面通過分析源碼看看如何刪除定時器的。

⑴處判斷定時器swtmrId是否超過OS_SWTMR_MAX_TIMERID,如果超過則返回錯誤碼。如果定時器編號沒有問題,獲取定時器控制塊LosSwtmrCB *swtmr。

⑵處判斷要刪除的定時器swtmrId是否匹配,不匹配則返回錯誤碼。

⑶處判斷定時器的狀態,如果定時器定時器沒有創建,不能刪除。如果定時器計時中,需要先停止OsSwtmrStop(swtmr),然后再刪除OsSwtmrDelete(swtmr)。

  1. LITE_OS_SEC_TEXT UINT32 LOS_SwtmrDelete(UINT32 swtmrId) 
  2.     SWTMR_CTRL_S *swtmr = NULL
  3.     UINT32 intSave; 
  4.     UINT32 ret = LOS_OK; 
  5.     UINT16 swtmrCbId; 
  6.  
  7. ⑴  if (swtmrId >= OS_SWTMR_MAX_TIMERID) { 
  8.         return LOS_ERRNO_SWTMR_ID_INVALID; 
  9.     } 
  10.     intSave = LOS_IntLock(); 
  11.     swtmrCbId = swtmrId % LOSCFG_BASE_CORE_SWTMR_LIMIT; 
  12.     swtmr = g_swtmrCBArray + swtmrCbId; 
  13. ⑵  if (swtmr->usTimerID != swtmrId) { 
  14.         LOS_IntRestore(intSave); 
  15.         return LOS_ERRNO_SWTMR_ID_INVALID; 
  16.     } 
  17.  
  18. ⑶  switch (swtmr->ucState) { 
  19.         case OS_SWTMR_STATUS_UNUSED: 
  20.             ret = LOS_ERRNO_SWTMR_NOT_CREATED; 
  21.             break; 
  22.         case OS_SWTMR_STATUS_TICKING: 
  23.             OsSwtmrStop(swtmr); 
  24.             /* fall through */ 
  25.         case OS_SWTMR_STATUS_CREATED: 
  26.             OsSwtmrDelete(swtmr); 
  27.             break; 
  28.         default
  29.             ret = LOS_ERRNO_SWTMR_STATUS_INVALID; 
  30.             break; 
  31.     } 
  32.  
  33.     LOS_IntRestore(intSave); 
  34.     return ret; 

接下來,我們繼續看看如何調用函數OsSwtmrDelete(swtmr)刪除定時器。函數特別簡單,把定時器放入空閑定時器鏈表g_swtmrFreeList頭部,然后把定時器狀態改為未使用狀態就完成了刪除。

  1. STATIC_INLINE VOID OsSwtmrDelete(SWTMR_CTRL_S *swtmr) 
  2.     /* insert to free list */ 
  3.     swtmr->pstNext = g_swtmrFreeList; 
  4.     g_swtmrFreeList = swtmr; 
  5.     swtmr->ucState = OS_SWTMR_STATUS_UNUSED; 
  6.  
  7. #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1) 
  8.     (VOID)memset_s((VOID *)&g_swtmrAlignID[swtmr->usTimerID % LOSCFG_BASE_CORE_SWTMR_LIMIT], 
  9.                    sizeof(SwtmrAlignData), 0, sizeof(SwtmrAlignData)); 
  10. #endif 

3.3 定時器啟動

創建完畢定時器后,我們可以使用函數LOS_SwtmrStart(UINT32 swtmrId)來啟動定時器,下面通過分析源碼看看如何啟動定時器的。

⑴處判斷定時器swtmrId是否超過OS_SWTMR_MAX_TIMERID,如果超過則返回錯誤碼。如果定時器編號沒有問題,獲取定時器控制塊LosSwtmrCB *swtmr。

⑵處判斷要啟動的定時器swtmrId是否匹配,不匹配則返回錯誤碼。

⑶處判斷定時器的狀態,如果定時器定時器沒有創建,不能啟動。如果定時器計時中,需要先停止OsSwtmrStop(swtmr),然后再啟動OsSwtmrStart(swtmr)。

  1. LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStart(UINT32 swtmrId) 
  2.     UINT32 intSave; 
  3.     UINT32 ret = LOS_OK; 
  4.  
  5. ⑴  if (swtmrId >= OS_SWTMR_MAX_TIMERID) { 
  6.         return LOS_ERRNO_SWTMR_ID_INVALID; 
  7.     } 
  8.  
  9.     intSave = LOS_IntLock(); 
  10.     SWTMR_CTRL_S *swtmr = g_swtmrCBArray + swtmrId % LOSCFG_BASE_CORE_SWTMR_LIMIT; 
  11. ⑵  if (swtmr->usTimerID != swtmrId) { 
  12.         LOS_IntRestore(intSave); 
  13.         return LOS_ERRNO_SWTMR_ID_INVALID; 
  14.     } 
  15.  
  16. #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1) 
  17.     if ((swtmr->ucSensitive == OS_SWTMR_ALIGN_INSENSITIVE) && (swtmr->ucMode == LOS_SWTMR_MODE_PERIOD)) { 
  18.         UINT32 swtmrAlignIdIndex = swtmr->usTimerID % LOSCFG_BASE_CORE_SWTMR_LIMIT; 
  19.         g_swtmrAlignID[swtmrAlignIdIndex].canAlign = 1; 
  20.         if ((swtmr->uwInterval % LOS_COMMON_DIVISOR) == 0) { 
  21.             g_swtmrAlignID[swtmrAlignIdIndex].canMultiple = 1; 
  22.             g_swtmrAlignID[swtmrAlignIdIndex].times = swtmr->uwInterval / LOS_COMMON_DIVISOR; 
  23.         } 
  24.     } 
  25. #endif 
  26.  
  27. ⑶  switch (swtmr->ucState) { 
  28.         case OS_SWTMR_STATUS_UNUSED: 
  29.             ret = LOS_ERRNO_SWTMR_NOT_CREATED; 
  30.             break; 
  31.         case OS_SWTMR_STATUS_TICKING: 
  32.             OsSwtmrStop(swtmr); 
  33.             /* fall through */ 
  34.         case OS_SWTMR_STATUS_CREATED: 
  35.             OsSwtmrStart(swtmr); 
  36.             break; 
  37.         default
  38.             ret = LOS_ERRNO_SWTMR_STATUS_INVALID; 
  39.             break; 
  40.     } 
  41.  
  42.     LOS_IntRestore(intSave); 
  43.     return ret; 

接下來,我們繼續看看如何調用函數OsSwtmrStart(swtmr)啟動定時器。函數特別簡單,⑴設置定時器的等待超時時間,并把定時器狀態改為計時中。⑵處把該定時器插入超時排序鏈表中。如果已使能任務調度,則修改過期時間。

  1. LITE_OS_SEC_TEXT VOID OsSwtmrStart(SWTMR_CTRL_S *swtmr) 
  2.     UINT64 currTime = OsGetCurrSchedTimeCycle(); 
  3.  
  4. ⑴  swtmr->uwCount = swtmr->uwInterval; 
  5.     swtmr->ucState = OS_SWTMR_STATUS_TICKING; 
  6.  
  7. #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1) 
  8.     if ((g_swtmrAlignID[swtmr->usTimerID % LOSCFG_BASE_CORE_SWTMR_LIMIT].canAlign == 1) && 
  9.         (g_swtmrAlignID[swtmr->usTimerID % LOSCFG_BASE_CORE_SWTMR_LIMIT].isAligned == 0)) { 
  10.         g_swtmrAlignID[swtmr->usTimerID % LOSCFG_BASE_CORE_SWTMR_LIMIT].isAligned = 1; 
  11.         OsSwtmrFindAlignPos(currTime, swtmr); 
  12.     } 
  13. #endif 
  14. ⑵  OsAdd2SortLink(&swtmr->stSortList, currTime, swtmr->uwCount, OS_SORT_LINK_SWTMR); 
  15.     if (LOS_TaskIsRunning()) { 
  16. ⑶      OsSchedUpdateExpireTime(currTime); 
  17.     } 

3.4 定時器停止

我們可以使用函數LOS_SwtmrStop(UINT32 swtmrId)來停止定時器,下面通過分析源碼看看如何停止定時器的。

⑴處判斷定時器swtmrId是否超過OS_SWTMR_MAX_TIMERID,如果超過則返回錯誤碼。如果定時器編號沒有問題,獲取定時器控制塊LosSwtmrCB *swtmr。

⑵處判斷要啟動的定時器swtmrId是否匹配,不匹配則返回錯誤碼。

⑶處判斷定時器的狀態,如果定時器定時器沒有創建,沒有啟動,不能停止。如果定時器計時中,會繼續調用OsSwtmrStop(swtmr)停止定時器。

  1. LITE_OS_SEC_TEXT UINT32 LOS_SwtmrStop(UINT32 swtmrId) 
  2.     SWTMR_CTRL_S *swtmr = NULL
  3.     UINT32 intSave; 
  4.     UINT16 swtmrCbId; 
  5.     UINT32 ret = LOS_OK; 
  6.  
  7. ⑴  if (swtmrId >= OS_SWTMR_MAX_TIMERID) { 
  8.         return LOS_ERRNO_SWTMR_ID_INVALID; 
  9.     } 
  10.     intSave = LOS_IntLock(); 
  11.     swtmrCbId = swtmrId % LOSCFG_BASE_CORE_SWTMR_LIMIT; 
  12.     swtmr = g_swtmrCBArray + swtmrCbId; 
  13. ⑵  if (swtmr->usTimerID != swtmrId) { 
  14.         LOS_IntRestore(intSave); 
  15.         return LOS_ERRNO_SWTMR_ID_INVALID; 
  16.     } 
  17.  
  18. ⑶  switch (swtmr->ucState) { 
  19.         case OS_SWTMR_STATUS_UNUSED: 
  20.             ret = LOS_ERRNO_SWTMR_NOT_CREATED; 
  21.             break; 
  22.         case OS_SWTMR_STATUS_CREATED: 
  23.             ret = LOS_ERRNO_SWTMR_NOT_STARTED; 
  24.             break; 
  25.         case OS_SWTMR_STATUS_TICKING: 
  26.             OsSwtmrStop(swtmr); 
  27.             break; 
  28.         default
  29.             ret = LOS_ERRNO_SWTMR_STATUS_INVALID; 
  30.             break; 
  31.     } 
  32.  
  33.     LOS_IntRestore(intSave); 
  34.     return ret; 

接下來,我們繼續看看如何調用函數OsSwtmrStop(swtmr)停止定時器。函數特別簡單,⑴處從排序鏈表中刪除該定時器的排序鏈表節點,更改定時器的狀態。⑵如果已使能任務調度,則修改過期時間。

  1. LITE_OS_SEC_TEXT VOID OsSwtmrStop(SWTMR_CTRL_S *swtmr) 
  2. ⑴  OsDeleteSortLink(&swtmr->stSortList, OS_SORT_LINK_SWTMR); 
  3.     swtmr->ucState = OS_SWTMR_STATUS_CREATED; 
  4.  
  5.     if (LOS_TaskIsRunning()) { 
  6. ⑵       OsSchedUpdateExpireTime(OsGetCurrSchedTimeCycle()); 
  7. #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1) 
  8.         g_swtmrAlignID[swtmr->usTimerID % LOSCFG_BASE_CORE_SWTMR_LIMIT].isAligned = 0; 
  9. #endif 
  10.     } 

4、定時器和Tick時間關系

定時器加入到超時排序鏈表后,隨時時間一個tick一個tick的逝去,需要不斷的檢查定時器是否超時到期。從之前的文章,已經知道系統每走過一個tick,系統就會調用一次Tick中斷的處理函數OsTickHandler(),該函數會調用定時器掃描函數OsSwtmrScan()來掃描、更新定時器時間。我們看下OsSwtmrScan()的代碼。

⑴處獲取超時排序鏈表的鏈表節點listObject,

⑵判斷排序鏈表是否為空,為空則返回。

⑶獲取排序鏈表的下一個鏈表節點sortList。

⑷循環遍歷超時排序鏈表上響應時間小于等于當前時間的鏈表節點,意味著定時器到期,需要處理定時器的回調函數。

⑸從超時排序鏈表中刪除超時的節點,

⑹獲取定時器控制塊SWTMR_CTRL_S *swtmr,調用函數OsSwtmrTimeoutHandle(swtmr)執行定時器回調函數,并設置需要調度的標記needSchedule。

⑺如果超時排序鏈表為空則終止循環。

  1. STATIC BOOL OsSwtmrScan(VOID) 
  2.     BOOL needSchedule = FALSE
  3. ⑴  LOS_DL_LIST *listObject = &g_swtmrSortLinkList->sortLink; 
  4.  
  5. ⑵  if (LOS_ListEmpty(listObject)) { 
  6.         return needSchedule; 
  7.     } 
  8.  
  9. ⑶  SortLinkList *sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode); 
  10.     UINT64 currTime = OsGetCurrSchedTimeCycle(); 
  11. ⑷  while (sortList->responseTime <= currTime) { 
  12. ⑸      OsDeleteNodeSortLink(g_swtmrSortLinkList, sortList); 
  13.  
  14. ⑹      SWTMR_CTRL_S *swtmr = LOS_DL_LIST_ENTRY(sortList, SWTMR_CTRL_S, stSortList); 
  15.         OsSwtmrTimeoutHandle(swtmr); 
  16.  
  17.         needSchedule = TRUE
  18. ⑺      if (LOS_ListEmpty(listObject)) { 
  19.             break; 
  20.         } 
  21.  
  22.         sortList = LOS_DL_LIST_ENTRY(listObject->pstNext, SortLinkList, sortLinkNode); 
  23.     } 
  24.  
  25.     return needSchedule; 

我們最后看下函數OsSwtmrTimeoutHandle()。

⑴處把定時器回調函數寫入定時器隊列。

⑵如果是一次性定時器,會把這個定時器刪除,回收到空閑定時器鏈表,狀態設置為未使用狀態,然后更新定時器的編號timerId。

⑶如果定時器屬于周期性定時器,重新啟動定時器。

⑷如果是一次性定時器但不刪除,則把定時器狀態設置為創建狀態。

  1. STATIC VOID OsSwtmrTimeoutHandle(SWTMR_CTRL_S *swtmr) 
  2.     SwtmrHandlerItem swtmrHandler; 
  3.  
  4.     swtmrHandler.handler = swtmr->pfnHandler; 
  5.     swtmrHandler.arg = swtmr->uwArg; 
  6.  
  7. ⑴  (VOID)LOS_QueueWriteCopy(g_swtmrHandlerQueue, &swtmrHandler, sizeof(SwtmrHandlerItem), LOS_NO_WAIT); 
  8. ⑵  if (swtmr->ucMode == LOS_SWTMR_MODE_ONCE) { 
  9.         OsSwtmrDelete(swtmr); 
  10.         if (swtmr->usTimerID < (OS_SWTMR_MAX_TIMERID - LOSCFG_BASE_CORE_SWTMR_LIMIT)) { 
  11.             swtmr->usTimerID += LOSCFG_BASE_CORE_SWTMR_LIMIT; 
  12.         } else { 
  13.             swtmr->usTimerID %= LOSCFG_BASE_CORE_SWTMR_LIMIT; 
  14.         } 
  15. ⑶  } else if (swtmr->ucMode == LOS_SWTMR_MODE_PERIOD) { 
  16.         OsSwtmrStart(swtmr); 
  17. ⑷  } else if (swtmr->ucMode == LOS_SWTMR_MODE_NO_SELFDELETE) { 
  18.         swtmr->ucState = OS_SWTMR_STATUS_CREATED; 
  19.     } 

小結

本文帶領大家一起剖析了鴻蒙輕內核的定時器模塊的源代碼,包含定時器的結構體、定時器池初始化、定時器創建、刪除、啟動停止等。

想了解更多內容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術社區

https://harmonyos.51cto.com

 

責任編輯:jianghua 來源: 鴻蒙社區
相關推薦

2021-06-09 09:48:01

鴻蒙HarmonyOS應用

2021-05-25 09:28:34

鴻蒙HarmonyOS應用

2022-01-12 10:50:23

鴻蒙HarmonyOS應用

2022-01-10 15:31:44

鴻蒙HarmonyOS應用

2021-06-04 09:57:49

鴻蒙HarmonyOS應用

2021-05-17 09:28:59

鴻蒙HarmonyOS應用

2021-05-08 15:14:50

鴻蒙HarmonyOS應用

2021-06-04 14:15:10

鴻蒙HarmonyOS應用

2021-10-20 16:08:57

鴻蒙HarmonyOS應用

2021-05-31 20:30:55

鴻蒙HarmonyOS應用

2022-03-11 20:23:14

鴻蒙源碼分析進程管理

2022-04-13 11:02:12

鴻蒙事件模塊事件Event

2022-03-03 18:28:28

Harmony進程任務管理模塊

2021-07-06 09:45:03

鴻蒙HarmonyOS應用

2021-09-22 14:36:32

鴻蒙HarmonyOS應用

2021-05-11 09:54:55

鴻蒙HarmonyOS應用

2021-05-21 09:25:11

鴻蒙HarmonyOS應用

2022-01-14 08:39:47

鴻蒙HarmonyOS應用

2021-05-10 15:05:56

鴻蒙HarmonyOS應用

2021-04-30 15:06:34

鴻蒙HarmonyOS應用
點贊
收藏

51CTO技術棧公眾號

国产在线精品日韩| 久久视频国产精品免费视频在线| 精品成a人在线观看| 国产成人综合av| 91无套直看片红桃在线观看| 高清久久一区| 午夜不卡av在线| 四虎影院一区二区三区 | 欧美伊人久久| 日韩av网站电影| 免费一区二区三区在线观看| 黄网在线免费看| 久久伊99综合婷婷久久伊| 国产精品视频自拍| 国产波霸爆乳一区二区| 曰本一区二区三区视频| 日韩一二三区视频| 人人干人人视频| 黄色美女视频在线观看| 国产精品素人一区二区| 99在线影院| 久久亚洲精品石原莉奈| 好吊日精品视频| 色青青草原桃花久久综合| 娇妻高潮浓精白浆xxⅹ| 亚洲人成777| 色综合久久综合网97色综合 | 久久99精品久久久久子伦| 亚洲午夜精品久久久| 亚洲精品社区| 欧美成人午夜影院| 中文字幕求饶的少妇| 亚洲视频分类| 亚洲精品电影在线| 亚洲av综合色区无码另类小说| 日本黄色成人| 在线观看日韩毛片| 国产肥臀一区二区福利视频| 波多野结衣中文字幕久久| 成人免费在线播放视频| 亚洲乱码一区二区三区 | 国产成人一二片| 91精品国产色综合久久ai换脸| 爱情岛论坛vip永久入口| 激情黄产视频在线免费观看| 亚洲午夜在线观看视频在线| 美女在线免费视频| 国产精品一卡二卡三卡| 一区在线观看视频| 一本一本久久a久久精品综合妖精| 免费黄色片在线观看| 99精品黄色片免费大全| 国产精品裸体一区二区三区| 亚洲va久久久噜噜噜无码久久| 国内外成人在线视频| 国产在线观看一区二区三区| 中文字幕第31页| 美女mm1313爽爽久久久蜜臀| 国产精品美女主播| 亚洲综合免费视频| 久久精品99国产精品日本| 国产精品自拍网| 国产又黄又猛又爽| 国产精品一区二区在线观看网站| 亚洲一区二区三区成人在线视频精品 | 国产在线一二三区| 国产日本一区二区| 婷婷精品国产一区二区三区日韩| 搞黄视频免费在线观看| 国产精品美女久久久久久2018| 亚洲人久久久| 国产精品剧情| 亚洲午夜久久久久| 久久无码高潮喷水| 欧美暴力调教| 欧美精品免费视频| 欧美日韩一区二区区别是什么| 动漫av一区| 亚洲免费电影一区| 亚洲毛片亚洲毛片亚洲毛片| 亚洲天天影视网| 久久久亚洲国产| 少妇太紧太爽又黄又硬又爽| 免费人成精品欧美精品| 亚洲自拍小视频| 无套内谢的新婚少妇国语播放| 久久精品网站免费观看| 中文字幕久久综合| 僵尸再翻生在线观看免费国语| 日韩欧美亚洲范冰冰与中字| 亚洲免费999| 精品国内亚洲2022精品成人| 亚洲午夜国产成人av电影男同| 国内毛片毛片毛片毛片毛片| 影音先锋久久| 国产日韩综合一区二区性色av| 性少妇videosexfreexxx片| 99免费精品在线| 中文字幕一区综合| 美女扒开腿让男人桶爽久久软| 在线免费观看成人短视频| 先锋资源在线视频| 国产中文精品久高清在线不| 欧美刺激性大交免费视频| 性无码专区无码| 国精产品一区一区三区mba视频| 精品产品国产在线不卡| 麻豆传媒视频在线观看免费| 欧美色videos| 国产精品99久久久精品无码| 精品欧美久久| 97国产精品免费视频| 国产一区二区在线视频聊天| 久久网站热最新地址| 成人短视频在线观看免费| gogo亚洲高清大胆美女人体| 亚洲成人久久久| 国产稀缺精品盗摄盗拍| 老司机精品视频网站| 国产精品国产一区二区| 黄网站在线免费| 91黄色免费版| 一区二区视频观看| 欧美午夜影院| 91嫩草在线视频| av资源种子在线观看| 欧美视频中文在线看| 特级特黄刘亦菲aaa级| 88国产精品视频一区二区三区| 日韩av大片在线| 男人天堂综合网| 亚洲日韩欧美一区二区在线| av五月天在线| 亚洲婷婷丁香| 欧美专区福利在线| 深夜影院在线观看| 精品国产福利视频| 91精品又粗又猛又爽| 欧美日韩亚洲一区二区三区在线| 国产一区二区丝袜| www.av在线播放| 欧美在线不卡视频| 久久久久久久久福利| 久久精品中文| 日韩精品欧美在线| 日本欧美不卡| 国产亚洲免费的视频看| 免费又黄又爽又猛大片午夜| 26uuu色噜噜精品一区二区| 免费无码不卡视频在线观看| 欧美一区自拍| 欧美一区第一页| 国产在线视频你懂得| 欧美在线观看视频一区二区三区| 男女做爰猛烈刺激| 日本免费在线视频不卡一不卡二| 日本高清不卡一区二区三| 2019年精品视频自拍| 中文字幕无线精品亚洲乱码一区 | 欧美一级一片| 人人爽久久涩噜噜噜网站| 欧美伦理影视网| 色欧美日韩亚洲| 日本不卡一区视频| 国产一区二区免费看| 五月天激情图片| 国产精品白浆| 日韩美女av在线免费观看| av资源种子在线观看| 91精品婷婷国产综合久久性色| 国产黄在线免费观看| 粉嫩aⅴ一区二区三区四区| 日韩中字在线观看| 欧美极品中文字幕| 国产在线播放91| 91老司机福利在线| 国产亚洲精品综合一区91| 国产色视频在线| 五月婷婷欧美视频| 91社区视频在线观看| 国产激情一区二区三区四区 | 麻豆国产在线| 永久免费精品影视网站| 99精品国产99久久久久久97| 亚洲高清视频中文字幕| 无码人妻aⅴ一区二区三区69岛| 乱一区二区av| 亚洲美免无码中文字幕在线| 精品国产成人| 不卡一区二区三区四区五区| 在线精品亚洲欧美日韩国产| 久久精品国产视频| 亚洲av电影一区| 欧美日韩aaa| 西西44rtwww国产精品| 国产精品美女久久久久久久久久久 | 国产精品一区二区三区在线免费观看 | 韩国三级中文字幕hd久久精品| 91.com在线| 日韩av二区| 国内一区二区三区在线视频| 久久亚洲资源中文字| 国外成人在线视频| 黄a在线观看| 亚洲欧美在线第一页| 成人福利小视频| 在线观看国产日韩| 日韩精品一区三区| 亚洲视频资源在线| 水蜜桃av无码| 国产精品123区| www.亚洲高清| 天堂一区二区在线免费观看| 日韩av新片网| 影音先锋日韩在线| 亚洲欧洲精品一区二区| 日韩精品亚洲aⅴ在线影院| 91久久国产综合久久91精品网站| 韩国久久久久久| 国内精品久久久久| 国产黄网站在线观看| 亚洲丝袜在线视频| 日韩一级免费视频| 欧美成人三级电影在线| 一级黄色片在线观看| 91精品福利视频| 国产成人免费看| 同产精品九九九| 国产在线视频在线观看| 亚洲天堂2014| 国产1区2区3区4区| 亚洲欧洲一区二区三区| av免费播放网站| 欧美精彩视频一区二区三区| 一级性生活大片| 久久综合色播五月| 毛茸茸多毛bbb毛多视频| 成人永久免费视频| 极品白嫩少妇无套内谢| 国产高清精品久久久久| japan高清日本乱xxxxx| 国内国产精品久久| 日韩精品在线播放视频| 国产乱码精品一品二品| 捷克做爰xxxⅹ性视频| 韩国av一区二区三区四区| 手机在线国产视频| 国产一区二区调教| 色男人天堂av| 国产成人av影院| 日批在线观看视频| 99国产精品国产精品毛片| 五月天激情小说| 91免费看片在线观看| 中文字幕第4页| 国产精品私房写真福利视频| 91香蕉国产视频| 中文字幕字幕中文在线中不卡视频| 日韩在线视频免费看| 亚洲免费电影在线| 日韩激情一区二区三区| 激情亚洲一区二区三区四区 | 久久久久久视频| 一区二区三区.www| 亚洲视频免费播放| 色诱视频网站一区| 中文字幕欧美人妻精品一区蜜臀| 欧美视频在线一区| 99国产精品久久久久久久成人| 精品国产凹凸成av人导航| 深夜福利视频一区| 最近2019中文字幕第三页视频| 免费网站免费进入在线| 久久久久久久91| 丝袜美腿一区| 91视频国产一区| 激情视频极品美女日韩| 欧美福利精品| 天天做天天爱综合| 日韩av高清在线看片| 三级亚洲高清视频| 日韩a一级欧美一级| av在线不卡免费看| 日本午夜精品视频| 亚洲一区二区三区四区在线观看| 日韩在线视频免费播放| 欧美日韩日日摸| 特级丰满少妇一级aaaa爱毛片| 国产一区二区日韩| 欧美女同一区| 国产精品久久久久久一区二区| 日韩在线视频一区二区三区| 欧美日本国产精品| 综合久久综合| 一本久道中文无码字幕av| 国产精品88av| 黄色av免费播放| 欧美日韩国产专区| 国产欧美日韩成人| 亚洲欧美福利视频| 少妇av在线| 国产精品入口夜色视频大尺度| 国产精品45p| 2025韩国大尺度电影| 久久久久久夜| 欧美做受高潮中文字幕| 亚洲视频一二区| 国产寡妇亲子伦一区二区三区四区| 91精品国产综合久久香蕉的特点 | 国产免费一区二区三区最新不卡| 亚洲国产古装精品网站| www免费在线观看| 国产精品福利片| 人体久久天天| 黄色三级中文字幕| 激情丁香综合五月| 少妇无套高潮一二三区| 亚洲v日本v欧美v久久精品| 99视频在线观看免费| 色先锋资源久久综合5566| 在线免费av资源| 好吊妞www.84com只有这里才有精品| 午夜精品视频一区二区三区在线看| 免费激情视频在线观看| av电影在线观看一区| 免费无遮挡无码永久在线观看视频| 欧美三区在线观看| 久草在线免费福利资源| 欧美亚州一区二区三区| 国产精品极品国产中出| 奇米777四色影视在线看| 国产一区中文字幕| 91制片厂在线| 91精品在线观看入口| 欧美天天影院| 国产日韩在线精品av| 日韩一区三区| 天堂中文av在线| 亚洲女子a中天字幕| 国产精品久久久久久无人区| 日韩中文视频免费在线观看| 日本欧美韩国| 亚洲精品永久www嫩草| 免费观看日韩电影| 国产探花视频在线播放| 欧美性受极品xxxx喷水| 成人动漫在线免费观看| 国产精品久久国产精品99gif| 国产区精品区| 国产精品视频黄色| 国产精品毛片无遮挡高清| 中文字幕一区2区3区| 久久精品国产精品| 亚洲日本va中文字幕| h无码动漫在线观看| 91天堂素人约啪| 毛片在线免费播放| 日韩中文字幕在线视频播放| av日韩久久| 日韩av在线播放不卡| 久久综合九色综合97_久久久| 久久久久久无码精品大片| 怡红院精品视频| 麻豆视频久久| 天堂…中文在线最新版在线| 久久综合资源网| 亚洲系列第一页| 欧美富婆性猛交| 久久99免费视频| 小明看看成人免费视频| 一区二区三区欧美亚洲| 午夜性色福利影院| 国产精品久久久久高潮| 亚洲成av人电影| 精品视频站长推荐| 日本精品视频一区二区三区| 黄在线免费看| 国产呦系列欧美呦日韩呦| 日韩电影免费在线看| 日本黄色小说视频| 日韩电影中文字幕在线| 国产成人福利夜色影视| 女人床在线观看| 久久久国产午夜精品| 国产三级漂亮女教师| 欧美一区深夜视频| 中文字幕日韩一区二区不卡| a级在线观看视频| 欧美一区二区视频网站| 午夜影院一区| 影音先锋男人的网站| 26uuu亚洲综合色| 精品久久人妻av中文字幕| 国产999在线观看| 欧美激情一区| 午夜精产品一区二区在线观看的| 日韩视频在线观看一区二区| 亚洲高清黄色| 国产一区二区三区小说| 亚洲欧洲精品天堂一级|