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

鴻蒙輕內核M核源碼分析系列六任務及任務調度(2)任務模塊

開發
本文帶領大家一起剖析了鴻蒙輕內核任務模塊的源代碼,包含任務模塊的結構體,任務初始化過程源代碼,任務常用操作的源代碼。

[[399389]]

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

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

https://harmonyos.51cto.com

任務是操作系統一個重要的概念,是競爭系統資源的最小運行單元。任務可以使用或等待CPU、使用內存空間等系統資源,并獨立于其它任務運行。鴻蒙輕內核的任務模塊可以給用戶提供多個任務,實現任務間的切換,幫助用戶管理業務程序流程。

接下來,我們看下任務模塊的結構體,任務初始化,任務常用操作的源代碼。

1、任務模塊的結構體定義

在文件kernel\include\los_task.h定義的任務控制塊結構體LosTaskCB,源代碼如下,結構體成員的解釋見注釋部分。

  1. typedef struct { 
  2.     VOID                        *stackPointer;            /* 任務棧指針 */ 
  3.     UINT16                      taskStatus;               /* 任務狀態 */ 
  4.     UINT16                      priority;                 /* 任務優先級 */ 
  5.     INT32                       timeSlice;                /* 剩余的時間片 */ 
  6.     UINT32                      waitTimes; 
  7.     SortLinkList                sortList;                 /* 任務超時排序鏈表節點 */ 
  8.     UINT64                      startTime; 
  9.     UINT32                      stackSize;                /* 任務棧大小 */ 
  10.     UINT32                      topOfStack;               /* 棧頂指針 */ 
  11.     UINT32                      taskID;                   /* 任務編號Id */ 
  12.     TSK_ENTRY_FUNC              taskEntry;                /* 任務入口函數 */ 
  13.     VOID                        *taskSem;                 /* 任務持有的信號量 */ 
  14.     VOID                        *taskMux;                 /* 導致任務阻塞的互斥鎖 */ 
  15.     UINT32                      arg;                      /* 任務入口函數的參數 */ 
  16.     CHAR                        *taskName;                /* 任務名稱 */ 
  17.     LOS_DL_LIST                 pendList;                 /* 就緒隊列等鏈表節點 */ 
  18.     LOS_DL_LIST                 timerList;                /* 任務超時排序鏈表節點 */ 
  19.     EVENT_CB_S                  event; 
  20.     UINT32                      eventMask;                /* 事件掩碼 */ 
  21.     UINT32                      eventMode;                /* 事件模式 */ 
  22.     VOID                        *msg;                     /* 分給給隊列的內存*/ 
  23.     INT32                       errorNo; 
  24. } LosTaskCB; 

 另外一個比較重要的結構體是TSK_INIT_PARAM_S,創建任務時,需要指定任務初始化的參數。源代碼如下,結構體成員的解釋見注釋部分。

  1. typedef struct tagTskInitParam { 
  2.     TSK_ENTRY_FUNC       pfnTaskEntry;              /** 任務入口函數 */ 
  3.     UINT16               usTaskPrio;                /** 任務參數  */ 
  4.     UINT32               uwStackSize;               /** 任務棧大小 */ 
  5.     CHAR                 *pcName;                   /** 任務名稱  */ 
  6.     UINT32               uwResved;                  /** 保留  */ 
  7. } TSK_INIT_PARAM_S; 

 2、任務模塊初始化

在系統啟動時,在kernel\src\los_init.c中調用OsTaskInit()進行任務模塊初始化,還會調用OsIdleTaskCreate()創建空閑任務。

2.1 任務模塊初始化

函數OsTaskInit()定義在kernel\src\los_task.c,我們分析下這個函數的執行過程。

⑴處代碼根據開發板配置的最大任務數g_taskMaxNum,計算需要申請的內存大小size,為任務控制塊TCB數組(也叫作任務池)g_taskCBArray申請內存。為什么比最大任務數多申請一個呢?在刪除任務時會使用。下文分析刪除任務的源碼時再詳細講解其用意。

⑵處代碼初始化雙向鏈表g_losFreeTask用作空閑的任務鏈表、g_taskRecyleList可以回收的任務鏈表。

⑶處循環初始化每一個任務,任務狀態未使用OS_TASK_STATUS_UNUSED,初始化任務Id,并把任務掛在空閑任務鏈表上。

⑷處初始化全局變量LosTask g_losTask,該全局變量維護當前運行的任務和要調度執行的任務。初始化任務池時,設置當前運行的任務為g_taskCBArray[g_taskMaxNum]。⑸處空閑任務編號暫時設置為無效值,后續創建空閑任務時再設置空閑任務編號。

優先級隊列,詳細的代碼實現剖析,參見之前的源碼剖析文章。⑸處互斥鎖死鎖檢測的調測特性的,后續系列文章專題進行講解。⑹處代碼初始化排序鏈表,詳細的代碼實現剖析,參見之前的源碼剖析文章。⑺處如果開啟了惰性棧,計算TCB的成員變量stackFrame在其結構體中的偏移量g_stackFrameOffLenInTcb。

  1. LITE_OS_SEC_TEXT_INIT UINT32 OsTaskInit(VOID) 
  2.     UINT32 size
  3.     UINT32 index
  4.  
  5. ⑴  size = (g_taskMaxNum + 1) * sizeof(LosTaskCB); 
  6.     g_taskCBArray = (LosTaskCB *)LOS_MemAlloc(m_aucSysMem0, size); 
  7.     if (g_taskCBArray == NULL) { 
  8.         return LOS_ERRNO_TSK_NO_MEMORY; 
  9.     } 
  10.     (VOID)memset_s(g_taskCBArray, size, 0, size); 
  11.  
  12. ⑵  LOS_ListInit(&g_losFreeTask); 
  13.     LOS_ListInit(&g_taskRecyleList); 
  14. ⑶  for (index = 0; index <= LOSCFG_BASE_CORE_TSK_LIMIT; index++) { 
  15.         g_taskCBArray[index].taskStatus = OS_TASK_STATUS_UNUSED; 
  16.         g_taskCBArray[index].taskID = index
  17.         LOS_ListTailInsert(&g_losFreeTask, &g_taskCBArray[index].pendList); 
  18.     } 
  19.  
  20.     // Ignore the return code when matching CSEC rule 6.6(4). 
  21. ⑷  (VOID)memset_s((VOID *)(&g_losTask), sizeof(g_losTask), 0, sizeof(g_losTask)); 
  22.     g_losTask.runTask = &g_taskCBArray[g_taskMaxNum]; 
  23.     g_losTask.runTask->taskID = index
  24.     g_losTask.runTask->taskStatus = (OS_TASK_STATUS_UNUSED | OS_TASK_STATUS_RUNNING); 
  25.     g_losTask.runTask->priority = OS_TASK_PRIORITY_LOWEST + 1; 
  26.  
  27. ⑸  g_idleTaskID = OS_INVALID; 
  28. ⑹  return OsSchedInit(); 

 2.2 創建空閑任務IdleCore000

除了初始化任務池,在系統啟動階段還會創建idle空閑任務。⑴處設置任務初始化參數時,空閑任務的入口執行函數為OsIdleTask()。⑵處調用函數把空閑任務狀態設置為就緒狀態。

  1. LITE_OS_SEC_TEXT_INIT UINT32 OsIdleTaskCreate(VOID) 
  2.     UINT32 retVal; 
  3.     TSK_INIT_PARAM_S taskInitParam; 
  4.     // Ignore the return code when matching CSEC rule 6.6(4). 
  5.     (VOID)memset_s((VOID *)(&taskInitParam), sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); 
  6. ⑴  taskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)OsIdleTask; 
  7.     taskInitParam.uwStackSize = LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE; 
  8.     taskInitParam.pcName = "IdleCore000"
  9.     taskInitParam.usTaskPrio = OS_TASK_PRIORITY_LOWEST; 
  10.     retVal = LOS_TaskCreateOnly(&g_idleTaskID, &taskInitParam); 
  11.  
  12.     if (retVal != LOS_OK) { 
  13.         return retVal; 
  14.     } 
  15.  
  16. ⑵  OsSchedSetIdleTaskSchedPartam(OS_TCB_FROM_TID(g_idleTaskID)); 
  17.     return LOS_OK; 

 我們看下空閑任務的入口執行函數為OsIdleTask(),它調用OsRecyleFinishedTask()回收任務棧資源,后文會分析如何回收任務資源。

  1. LITE_OS_SEC_TEXT WEAK VOID OsIdleTask(VOID) 
  2.     while (1) { 
  3.         OsRecyleFinishedTask(); 
  4.         HalEnterSleep(OS_SYS_DEEP_SLEEP); 
  5.     } 

 3、任務模塊常用操作

3.1 創建和刪除任務

3.1.1 創建任務

鴻蒙輕內核提供了2個創建任務的函數,有LOS_TaskCreate、LOS_TaskCreateOnly。LOS_TaskCreate和LOS_TaskCreateOnly的區別是,前者創建任務完畢就使任務進入就緒狀態,并觸發調度,如果就緒隊列中沒有更高優先級的任務,則運行該任務。后者只創建任務,設置任務狀態為阻塞suspend狀態,需要開發者去調用LOS_TaskResume使該任務進入ready狀態。

函數LOS_TaskCreate代碼如下,可以看出創建任務的時候,調用⑴處的函數LOS_TaskCreateOnly()來創建任務。創建任務后,執行⑵處的代碼使任務進入ready就緒隊列,如果系統啟動完成,允許任務調度,則執行⑶觸發任務調度。如果新創建的任務優先級最高,則會被調度運行。 

  1. LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreate(UINT32 *taskID, TSK_INIT_PARAM_S *taskInitParam) 
  2.     UINT32 retVal; 
  3.     UINTPTR intSave; 
  4.     LosTaskCB *taskCB = NULL
  5.  
  6. ⑴  retVal = LOS_TaskCreateOnly(taskID, taskInitParam); 
  7.     if (retVal != LOS_OK) { 
  8.         return retVal; 
  9.     } 
  10.     taskCB = OS_TCB_FROM_TID(*taskID); 
  11.  
  12.     intSave = LOS_IntLock(); 
  13. #if (LOSCFG_BASE_CORE_CPUP == 1) 
  14.     g_cpup[taskCB->taskID].cpupID = taskCB->taskID; 
  15.     g_cpup[taskCB->taskID].status = taskCB->taskStatus; 
  16. #endif 
  17.  
  18. ⑵  OsSchedTaskEnQueue(taskCB); 
  19.     LOS_IntRestore(intSave); 
  20.  
  21. ⑶  if (g_taskScheduled) { 
  22.         LOS_Schedule(); 
  23.     } 
  24.  
  25.     return LOS_OK; 

我們接著分析下如何使用函數UINT32 LOS_TaskCreateOnly()創建任務。⑴處調用OsTaskInitParamCheck()檢測創建任務的參數的合法性。⑵處調用函數回收釋放的任務。⑶處如果任務池為空,無法創建任務,返回錯誤碼。⑷處從任務池獲取一個空閑的任務控制塊taskCB,然后從空閑任務鏈表中刪除。⑸處根據指定的任務棧大小為任務棧申請內存,⑹處判斷任務棧內存申請釋放成功,如果申請失敗,則把任務控制塊歸還到空閑任務鏈表中,并返回錯誤碼。⑺處調用函數初始化任務棧,更新任務控制塊成員信息。詳細見后面對該函數的分析。 

  1. LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreateOnly(UINT32 *taskID, TSK_INIT_PARAM_S *taskInitParam) 
  2.     UINTPTR intSave; 
  3.     VOID  *topOfStack = NULL
  4.     LosTaskCB *taskCB = NULL
  5.     UINT32 retVal; 
  6.  
  7.     if (taskID == NULL) { 
  8.         return LOS_ERRNO_TSK_ID_INVALID; 
  9.     } 
  10.  
  11. ⑴  retVal = OsTaskInitParamCheck(taskInitParam); 
  12.     if (retVal != LOS_OK) { 
  13.         return retVal; 
  14.     } 
  15.  
  16. ⑵  OsRecyleFinishedTask(); 
  17.  
  18.     intSave = LOS_IntLock(); 
  19. ⑶  if (LOS_ListEmpty(&g_losFreeTask)) { 
  20.         retVal = LOS_ERRNO_TSK_TCB_UNAVAILABLE; 
  21.         OS_GOTO_ERREND(); 
  22.     } 
  23.  
  24. ⑷  taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&g_losFreeTask)); 
  25.     LOS_ListDelete(LOS_DL_LIST_FIRST(&g_losFreeTask)); 
  26.  
  27.     LOS_IntRestore(intSave); 
  28.  
  29. #if (LOSCFG_EXC_HRADWARE_STACK_PROTECTION == 1) 
  30.     UINTPTR stackPtr = (UINTPTR)LOS_MemAllocAlign(OS_TASK_STACK_ADDR, taskInitParam->uwStackSize + 
  31.         OS_TASK_STACK_PROTECT_SIZE, OS_TASK_STACK_PROTECT_SIZE); 
  32.     topOfStack = (VOID *)(stackPtr + OS_TASK_STACK_PROTECT_SIZE); 
  33. #else 
  34. ⑸      topOfStack = (VOID *)LOS_MemAllocAlign(OS_TASK_STACK_ADDR, taskInitParam->uwStackSize, 
  35.         LOSCFG_STACK_POINT_ALIGN_SIZE); 
  36. #endif 
  37. ⑹  if (topOfStack == NULL) { 
  38.         intSave = LOS_IntLock(); 
  39.         LOS_ListAdd(&g_losFreeTask, &taskCB->pendList); 
  40.         LOS_IntRestore(intSave); 
  41.         return LOS_ERRNO_TSK_NO_MEMORY; 
  42.     } 
  43.  
  44. ⑺  retVal = OsNewTaskInit(taskCB, taskInitParam, topOfStack); 
  45.     if (retVal != LOS_OK) { 
  46.         return retVal; 
  47.     } 
  48.  
  49.     *taskID = taskCB->taskID; 
  50.     OsHookCall(LOS_HOOK_TYPE_TASK_CREATE, taskCB); 
  51.     return retVal; 
  52.  
  53. LOS_ERREND: 
  54.     LOS_IntRestore(intSave); 
  55.     return retVal; 

 我們看下創建任務函數調用的函數OsRecyleFinishedTask(),該函數在系統進入空閑時也會調用。刪除運行狀態的任務時,會把任務掛在雙向鏈表里g_taskRecyleList。任務回收函數就用來回收此類任務,實現任務資源回收。我們分析下它的代碼。⑴處循環遍歷回收鏈表,⑵從回收鏈表獲取第一個任務taskCB,從回收鏈表刪除并插入到空閑任務鏈表里。任務棧保護在后續系列再深入分析,繼續往下看代碼,⑶處獲取任務棧棧頂指針,接著調用內存釋放函數來釋放任務棧占用的內存,并設置任務棧的棧頂為空。

  1. STATIC VOID OsRecyleFinishedTask(VOID) 
  2.     LosTaskCB *taskCB = NULL
  3.     UINTPTR intSave; 
  4.     UINTPTR stackPtr; 
  5.  
  6.     intSave = LOS_IntLock(); 
  7. ⑴  while (!LOS_ListEmpty(&g_taskRecyleList)) { 
  8. ⑵      taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&g_taskRecyleList)); 
  9.         LOS_ListDelete(LOS_DL_LIST_FIRST(&g_taskRecyleList)); 
  10.         LOS_ListAdd(&g_losFreeTask, &taskCB->pendList); 
  11. #if (LOSCFG_EXC_HRADWARE_STACK_PROTECTION == 1) 
  12.         stackPtr = taskCB->topOfStack - OS_TASK_STACK_PROTECT_SIZE; 
  13. #else 
  14. ⑶      stackPtr = taskCB->topOfStack; 
  15. #endif 
  16.         (VOID)LOS_MemFree(OS_TASK_STACK_ADDR, (VOID *)stackPtr); 
  17.         taskCB->topOfStack = (UINT32)NULL
  18.     } 
  19.     LOS_IntRestore(intSave); 

 我們繼續分析下函數OsNewTaskInit(),⑴處調用函數初始化任務棧,上一系列已經分析過該函數,代碼的其余部分用來更新任務控制塊的成員信息,比如⑵處任務狀態設置為阻塞狀態。

  1. LITE_OS_SEC_TEXT_INIT UINT32 OsNewTaskInit(LosTaskCB *taskCB, TSK_INIT_PARAM_S *taskInitParam, VOID *topOfStack) 
  2. ⑴  taskCB->stackPointer    = HalTskStackInit(taskCB->taskID, taskInitParam->uwStackSize, topOfStack); 
  3.     taskCB->arg             = taskInitParam->uwArg; 
  4.     taskCB->topOfStack      = (UINT32)(UINTPTR)topOfStack; 
  5.     taskCB->stackSize       = taskInitParam->uwStackSize; 
  6.     taskCB->taskSem         = NULL
  7.     taskCB->taskMux         = NULL
  8. ⑵  taskCB->taskStatus      = OS_TASK_STATUS_SUSPEND; 
  9.     taskCB->priority        = taskInitParam->usTaskPrio; 
  10.     taskCB->timeSlice       = 0; 
  11.     taskCB->waitTimes       = 0; 
  12.     taskCB->taskEntry       = taskInitParam->pfnTaskEntry; 
  13.     taskCB->event.uwEventID = OS_NULL_INT; 
  14.     taskCB->eventMask       = 0; 
  15.     taskCB->taskName        = taskInitParam->pcName; 
  16.     taskCB->msg             = NULL
  17.     SET_SORTLIST_VALUE(&taskCB->sortList, OS_SORT_LINK_INVALID_TIME); 
  18.     return LOS_OK; 

 3.1.2 刪除任務UINT32 LOS_TaskDelete()

該函數根據傳入的參數UINT32 taskId刪除任務。我們分析下刪除任務的源代碼,⑴處檢驗傳入的參數,⑵處如果任務還未創建,返回錯誤碼。⑶處如果刪除的任務正在運行,又處于鎖任務調度情況下,打印信息,告訴用戶不推薦在鎖任務調度期間進行任務刪除,然后執行⑷,把全局變量賦值0來解鎖任務調度。

⑸處調用函數處理任務狀態,如果處于就緒狀態設置為非就緒狀態,并從就緒隊列刪除。如果處于阻塞狀態,從阻塞隊列中刪除。如果任務處于超時等待狀態,從超時排序鏈表中刪除。⑹恢復任務控制塊事件相關的成員信息。⑺如果任務正在運行,設置任務為未使用狀態,接著調用函數OsRunningTaskDelete()把任務放入回收鏈表,然后主動觸發任務調度,稍后詳細分析該函數。如果刪除的任務不是出于運行狀態,則執行⑻,設置任務為未使用狀態,接著把任務回收到空閑任務鏈表里,然后獲取任務棧的棧頂指針,調用內存釋放函數釋放任務棧的內存。

  1. LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskDelete(UINT32 taskID) 
  2.     UINTPTR intSave; 
  3.     LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID); 
  4.     UINTPTR stackPtr; 
  5.  
  6. ⑴  UINT32 ret = OsCheckTaskIDValid(taskID); 
  7.     if (ret != LOS_OK) { 
  8.         return ret; 
  9.     } 
  10.  
  11.     intSave = LOS_IntLock(); 
  12.  
  13. ⑵  if ((taskCB->taskStatus) & OS_TASK_STATUS_UNUSED) { 
  14.         LOS_IntRestore(intSave); 
  15.         return LOS_ERRNO_TSK_NOT_CREATED; 
  16.     } 
  17.  
  18.     /* If the task is running and scheduler is locked then you can not delete it */ 
  19. ⑶  if (((taskCB->taskStatus) & OS_TASK_STATUS_RUNNING) && (g_losTaskLock != 0)) { 
  20.         PRINT_INFO("In case of task lock, task deletion is not recommended\n"); 
  21. ⑷      g_losTaskLock = 0; 
  22.     } 
  23.  
  24.     OsHookCall(LOS_HOOK_TYPE_TASK_DELETE, taskCB); 
  25. ⑸  OsSchedTaskExit(taskCB); 
  26.  
  27. ⑹  taskCB->event.uwEventID = OS_NULL_INT; 
  28.     taskCB->eventMask = 0; 
  29. #if (LOSCFG_BASE_CORE_CPUP == 1) 
  30.     // Ignore the return code when matching CSEC rule 6.6(4). 
  31.     (VOID)memset_s((VOID *)&g_cpup[taskCB->taskID], sizeof(OsCpupCB), 0, sizeof(OsCpupCB)); 
  32. #endif 
  33.     if (taskCB->taskStatus & OS_TASK_STATUS_RUNNING) { 
  34. ⑺      taskCB->taskStatus = OS_TASK_STATUS_UNUSED; 
  35.         OsRunningTaskDelete(taskID, taskCB); 
  36.         LOS_IntRestore(intSave); 
  37.         LOS_Schedule(); 
  38.         return LOS_OK; 
  39.     } else { 
  40. ⑻       taskCB->taskStatus = OS_TASK_STATUS_UNUSED; 
  41.         LOS_ListAdd(&g_losFreeTask, &taskCB->pendList); 
  42. #if (LOSCFG_EXC_HRADWARE_STACK_PROTECTION == 1) 
  43.         stackPtr = taskCB->topOfStack - OS_TASK_STACK_PROTECT_SIZE; 
  44. #else 
  45.         stackPtr = taskCB->topOfStack; 
  46. #endif 
  47.         (VOID)LOS_MemFree(OS_TASK_STACK_ADDR, (VOID *)stackPtr); 
  48.         taskCB->topOfStack = (UINT32)NULL
  49.     } 
  50.  
  51.     LOS_IntRestore(intSave); 
  52.     return LOS_OK; 

 我們看下函數OsRunningTaskDelete()的源碼。⑴處把當前運行的任務放入待回收鏈表里,然后執行⑵把當前運行的任務放入任務池的最后一個位置g_taskCBArray[g_taskMaxNum]。為什么這么操作呢?等后續分析源碼的時候再來解答。

  1. LITE_OS_SEC_TEXT_INIT STATIC_INLINE VOID OsRunningTaskDelete(UINT32 taskID, LosTaskCB *taskCB) 
  2. ⑴  LOS_ListTailInsert(&g_taskRecyleList, &taskCB->pendList); 
  3. ⑵  g_losTask.runTask = &g_taskCBArray[g_taskMaxNum]; 
  4.     g_losTask.runTask->taskID = taskID; 
  5.     g_losTask.runTask->taskStatus = taskCB->taskStatus | OS_TASK_STATUS_RUNNING; 
  6.     g_losTask.runTask->topOfStack = taskCB->topOfStack; 
  7.     g_losTask.runTask->taskName = taskCB->taskName; 

 3.2 控制任務狀態

3.2.1 恢復掛起的任務LOS_TaskResume()

恢復掛起的任務,使該任務進入就緒狀態,和下文中的LOS_TaskSuspend()成對使用。⑴處獲取任務的TCB,⑵處對任務狀態進行判斷,如果任務未創建或者非阻塞狀態,則返回錯誤碼。執行⑶設置任務狀態為非掛起狀態。⑶處獲取任務的狀態進行判斷,如果任務沒有創建或者不是掛起狀態,則返回相應的錯誤碼。 ⑷檢查任務狀態是否為OS_CHECK_TASK_BLOCK,即(OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND | OS_TASK_STATUS_SUSPEND)中的一種,這幾個狀態影響恢復掛起的任務。如果非上述幾個狀態,執行⑸調用函數,把任務狀態改為就緒狀態,插入任務就緒隊列。如果支持支持調度,則執行⑹觸發調度。

  1. LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskResume(UINT32 taskID) 
  2.     UINTPTR intSave; 
  3.     LosTaskCB *taskCB = NULL
  4.     UINT16 tempStatus; 
  5.     UINT32 retErr = OS_ERROR; 
  6.  
  7.     if (taskID > LOSCFG_BASE_CORE_TSK_LIMIT) { 
  8.         return LOS_ERRNO_TSK_ID_INVALID; 
  9.     } 
  10.  
  11. ⑴  taskCB = OS_TCB_FROM_TID(taskID); 
  12.     intSave = LOS_IntLock(); 
  13.     tempStatus = taskCB->taskStatus; 
  14.  
  15. ⑵  if (tempStatus & OS_TASK_STATUS_UNUSED) { 
  16.         retErr = LOS_ERRNO_TSK_NOT_CREATED; 
  17.         OS_GOTO_ERREND(); 
  18.     } else if (!(tempStatus & OS_TASK_STATUS_SUSPEND)) { 
  19.         retErr = LOS_ERRNO_TSK_NOT_SUSPENDED; 
  20.         OS_GOTO_ERREND(); 
  21.     } 
  22.  
  23. ⑶  taskCB->taskStatus &= (~OS_TASK_STATUS_SUSPEND); 
  24. ⑷  if (!(taskCB->taskStatus & OS_CHECK_TASK_BLOCK)) { 
  25. ⑸      OsSchedTaskEnQueue(taskCB); 
  26.         if (g_taskScheduled) { 
  27.             LOS_IntRestore(intSave); 
  28. ⑹          LOS_Schedule(); 
  29.             return LOS_OK; 
  30.         } 
  31.     } 
  32.  
  33.     LOS_IntRestore(intSave); 
  34.     return LOS_OK; 
  35.  
  36. LOS_ERREND: 
  37.     LOS_IntRestore(intSave); 
  38.     return retErr; 

 3.2.2 掛起指定的任務LOS_TaskSuspend()

函數用于掛起指定的任務。⑴處獲取任務的TCB,⑵處開始獲取任務的狀態進行判斷,如果任務沒有創建、任務已經掛起,返回相應的錯誤碼。⑶處如果任務是運行狀態,并且鎖任務調度時,跳轉到LOS_ERREND結束掛起操作。⑷處如果任務是就緒狀態,調用函數從就緒隊列出隊,并取消任務的就緒狀態。⑸處語句設置任務狀態為阻塞狀態。⑹如果掛起的是當前運行的任務,則會主動觸發調度。

  1. LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskSuspend(UINT32 taskID) 
  2.     UINTPTR intSave; 
  3.     LosTaskCB *taskCB = NULL
  4.     UINT16 tempStatus; 
  5.     UINT32 retErr; 
  6.  
  7.     retErr = OsCheckTaskIDValid(taskID); 
  8.     if (retErr != LOS_OK) { 
  9.         return retErr; 
  10.     } 
  11.  
  12. ⑴  taskCB = OS_TCB_FROM_TID(taskID); 
  13.     intSave = LOS_IntLock(); 
  14. ⑵  tempStatus = taskCB->taskStatus; 
  15.     if (tempStatus & OS_TASK_STATUS_UNUSED) { 
  16.         retErr = LOS_ERRNO_TSK_NOT_CREATED; 
  17.         OS_GOTO_ERREND(); 
  18.     } 
  19.  
  20.     if (tempStatus & OS_TASK_STATUS_SUSPEND) { 
  21.         retErr = LOS_ERRNO_TSK_ALREADY_SUSPENDED; 
  22.         OS_GOTO_ERREND(); 
  23.     } 
  24.  
  25. ⑶  if ((tempStatus & OS_TASK_STATUS_RUNNING) && (g_losTaskLock != 0)) { 
  26.         retErr = LOS_ERRNO_TSK_SUSPEND_LOCKED; 
  27.         OS_GOTO_ERREND(); 
  28.     } 
  29.  
  30. ⑷  if (tempStatus & OS_TASK_STATUS_READY) { 
  31.         OsSchedTaskDeQueue(taskCB); 
  32.     } 
  33.  
  34. ⑸  taskCB->taskStatus |= OS_TASK_STATUS_SUSPEND; 
  35.     OsHookCall(LOS_HOOK_TYPE_MOVEDTASKTOSUSPENDEDLIST, taskCB); 
  36. ⑹  if (taskID == g_losTask.runTask->taskID) { 
  37.         LOS_IntRestore(intSave); 
  38.         LOS_Schedule(); 
  39.         return LOS_OK; 
  40.     } 
  41.  
  42.     LOS_IntRestore(intSave); 
  43.     return LOS_OK; 
  44.  
  45. LOS_ERREND: 
  46.     LOS_IntRestore(intSave); 
  47.     return retErr; 

 3.2.3 任務延時等待LOS_TaskDelay()

任務延時等待,釋放CPU,等待時間到期后該任務會重新進入就緒狀態。

⑴處代碼判斷系統處于中斷,如果是,則返回錯誤碼,不允許任務延時等待。

⑵如果處于鎖任務調度期間,則返回錯誤碼。

⑶處如果延遲的時間為0,則執行讓權操作,否則執行。

⑷調用函數OsSchedDelay()把當前任務設置為延時等待狀態,然后調用LOS_Schedule()觸發調度。

  1. LITE_OS_SEC_TEXT UINT32 LOS_TaskDelay(UINT32 tick) 
  2.     UINTPTR intSave; 
  3.  
  4. ⑴  if (OS_INT_ACTIVE) { 
  5.         return LOS_ERRNO_TSK_DELAY_IN_INT; 
  6.     } 
  7.  
  8. ⑵  if (g_losTaskLock != 0) { 
  9.         return LOS_ERRNO_TSK_DELAY_IN_LOCK; 
  10.     } 
  11.  
  12.     OsHookCall(LOS_HOOK_TYPE_TASK_DELAY, tick); 
  13. ⑶  if (tick == 0) { 
  14.         return LOS_TaskYield(); 
  15.     } else { 
  16.         intSave = LOS_IntLock(); 
  17. ⑷      OsSchedDelay(g_losTask.runTask, tick); 
  18.         OsHookCall(LOS_HOOK_TYPE_MOVEDTASKTODELAYEDLIST, g_losTask.runTask); 
  19.         LOS_IntRestore(intSave); 
  20.         LOS_Schedule(); 
  21.     } 
  22.  
  23.     return LOS_OK; 

 另外還提供了函數LOS_Msleep()和LOS_UDelay(),前者以毫秒為單位進行延遲等待。后者也是以毫秒為單位進行延遲等待,但是不會觸發任務調度,當前任務不會釋放CPU。

  1. LITE_OS_SEC_TEXT_MINOR VOID LOS_Msleep(UINT32 mSecs) 
  2.     UINT32 interval; 
  3.  
  4.     if (OS_INT_ACTIVE) { 
  5.         return
  6.     } 
  7.  
  8.     if (mSecs == 0) { 
  9.         interval = 0; 
  10.     } else { 
  11.         interval = LOS_MS2Tick(mSecs); 
  12.         if (interval == 0) { 
  13.             interval = 1; 
  14.         } 
  15.     } 
  16.  
  17.     (VOID)LOS_TaskDelay(interval); 
  18.  
  19. VOID LOS_UDelay(UINT64 microseconds) 
  20.     UINT64 endTime; 
  21.  
  22.     if (microseconds == 0) { 
  23.         return
  24.     } 
  25.  
  26.     endTime = (microseconds / OS_SYS_US_PER_SECOND) * OS_SYS_CLOCK + 
  27.             (microseconds % OS_SYS_US_PER_SECOND) * OS_SYS_CLOCK / OS_SYS_US_PER_SECOND; 
  28.     endTime = LOS_SysCycleGet() + endTime; 
  29.     while (LOS_SysCycleGet() < endTime) { 
  30.     } 
  31.  
  32.     return

 3.2.4 任務讓權LOS_TaskYield()

讓權函數通過把當前任務時間片設置為0,釋放CPU占用,重新調度給其他高優先級任務執行。⑴處調用函數把當前任務時間片設置為0,然后執行⑵主動觸發任務調度。

  1. LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskYield(VOID) 
  2.     UINTPTR intSave; 
  3.  
  4.     intSave = LOS_IntLock(); 
  5. ⑴  OsSchedYield(); 
  6.     LOS_IntRestore(intSave); 
  7. ⑵  LOS_Schedule(); 
  8.     return LOS_OK; 

 接下來看下函數OsSchedYield()的源碼。代碼很簡單,獲取當前運行的任務,然后把其時間片設置為0,如下:

  1. VOID OsSchedYield(VOID) 
  2.     LosTaskCB *runTask = g_losTask.runTask; 
  3.  
  4.     runTask->timeSlice = 0; 

 3.3 控制任務調度

3.3.1 鎖任務調度LOS_TaskLock()

鎖任務調度LOS_TaskLock()比較簡單,把任務鎖調度計數器全局變量增加1即可,代碼如下。

  1. LITE_OS_SEC_TEXT_MINOR VOID LOS_TaskLock(VOID) 
  2.     UINTPTR intSave; 
  3.  
  4.     intSave = LOS_IntLock(); 
  5.     g_losTaskLock++; 
  6.     LOS_IntRestore(intSave); 

 3.3.2 解鎖任務調度LOS_TaskUnlock()

我們看看解鎖任務調度函數LOS_TaskUnlock(),⑴處如果任務鎖調度計數器全局變量數值大于0,對其減1。⑵處如果任務鎖調度計數器等于0,則執行⑶處觸發調度。代碼如下:

  1. LITE_OS_SEC_TEXT_MINOR VOID LOS_TaskUnlock(VOID) 
  2.     UINTPTR intSave; 
  3.  
  4.     intSave = LOS_IntLock(); 
  5. ⑴  if (g_losTaskLock > 0) { 
  6.         g_losTaskLock--; 
  7. ⑵      if (g_losTaskLock == 0) { 
  8.             LOS_IntRestore(intSave); 
  9. ⑶          LOS_Schedule(); 
  10.             return
  11.         } 
  12.     } 
  13.  
  14.     LOS_IntRestore(intSave); 

 3.4 控制任務優先級

LiteOS-M內核支持動態設置任務的優先級,提供了一些操作。

3.4.1 設置指定任務的優先級LOS_TaskPriSet

支持設置指定任務Id的優先級,也支持對當前運行任務進行優先級設置。⑴處開始,做些基礎校驗,包含檢驗傳入的優先級參數taskPrio,指定任務的Id,任務是否未創建等,如果沒有通過參數校驗,則返回錯誤碼。⑵處調用函數設置任務優先級,稍后分析該函數。如果任務處于就緒狀態或者運行狀態,則會執行⑶主動觸發任務調度。

  1. LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskPriSet(UINT32 taskID, UINT16 taskPrio) 
  2.     BOOL isReady = FALSE
  3.     UINTPTR intSave; 
  4.     LosTaskCB *taskCB = NULL
  5.     UINT16 tempStatus; 
  6.  
  7. ⑴  if (taskPrio > OS_TASK_PRIORITY_LOWEST) { 
  8.         return LOS_ERRNO_TSK_PRIOR_ERROR; 
  9.     } 
  10.  
  11.     if (taskID == g_idleTaskID) { 
  12.         return LOS_ERRNO_TSK_OPERATE_IDLE; 
  13.     } 
  14.  
  15.     if (taskID == g_swtmrTaskID) { 
  16.         return LOS_ERRNO_TSK_OPERATE_SWTMR; 
  17.     } 
  18.  
  19.     if (OS_CHECK_TSK_PID_NOIDLE(taskID)) { 
  20.         return LOS_ERRNO_TSK_ID_INVALID; 
  21.     } 
  22.  
  23.     taskCB = OS_TCB_FROM_TID(taskID); 
  24.     intSave = LOS_IntLock(); 
  25.     tempStatus = taskCB->taskStatus; 
  26.     if (tempStatus & OS_TASK_STATUS_UNUSED) { 
  27.         LOS_IntRestore(intSave); 
  28.         return LOS_ERRNO_TSK_NOT_CREATED; 
  29.     } 
  30.  
  31. ⑵  isReady = OsSchedModifyTaskSchedParam(taskCB, taskPrio); 
  32.     LOS_IntRestore(intSave); 
  33.     if (isReady) { 
  34. ⑶      LOS_Schedule(); 
  35.     } 
  36.  
  37.     return LOS_OK; 

 接下來,我們分析下函數OsSchedModifyTaskSchedParam()。⑴處如果任務處于就緒狀態,需要先出隊設置優先級,然后入隊就緒隊列。如果非就緒狀態,可以直接執行⑵處語句修改任務優先級。如果任務正在運行,需要返回TRUE,標記下需要任務調度。

  1. BOOL OsSchedModifyTaskSchedParam(LosTaskCB *taskCB, UINT16 priority) 
  2.     if (taskCB->taskStatus & OS_TASK_STATUS_READY) { 
  3. ⑴      OsSchedTaskDeQueue(taskCB); 
  4.         taskCB->priority = priority; 
  5.         OsSchedTaskEnQueue(taskCB); 
  6.         return TRUE
  7.     } 
  8.  
  9. ⑵  taskCB->priority = priority; 
  10.     OsHookCall(LOS_HOOK_TYPE_TASK_PRIMODIFY, taskCB, taskCB->priority); 
  11.     if (taskCB->taskStatus & OS_TASK_STATUS_RUNNING) { 
  12.         return TRUE
  13.     } 
  14.  
  15.     return FALSE

 3.4.2 獲取指定任務的優先級LOS_TaskPriGet

獲取指定任務的優先級LOS_TaskPriGet()代碼比較簡單,⑴處如果任務編號無效,返回錯誤碼。⑵處如果任務未創建返回錯誤碼。如果參數校驗通過,執行⑶獲取任務的優先級數值。

  1. LITE_OS_SEC_TEXT_MINOR UINT16 LOS_TaskPriGet(UINT32 taskID) 
  2.     UINTPTR intSave; 
  3.     LosTaskCB *taskCB = NULL
  4.     UINT16 priority; 
  5.  
  6. ⑴  if (OS_CHECK_TSK_PID_NOIDLE(taskID)) { 
  7.         return (UINT16)OS_INVALID; 
  8.     } 
  9.  
  10.     taskCB = OS_TCB_FROM_TID(taskID); 
  11.  
  12.     intSave = LOS_IntLock(); 
  13.  
  14. ⑵  if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) { 
  15.         LOS_IntRestore(intSave); 
  16.         return (UINT16)OS_INVALID; 
  17.     } 
  18.  
  19. ⑶  priority = taskCB->priority; 
  20.     LOS_IntRestore(intSave); 
  21.     return priority; 

 3.5 任務阻塞和喚醒

最后,我們分析下函數OsSchedTaskWait()和OsSchedTaskWake(),這2個函數定義在文件kernel\src\los_sched.c中。任務在申請互斥鎖、信號量、出入隊列、讀寫事件時,都可能導致任務進入阻塞狀態,對應地也需要任務喚醒重新進入就緒隊列狀態。這2個函數就負責任務的阻塞和喚醒,我們分析下他們的代碼。

3.5.1 任務阻塞

我們分析下任務阻塞的函數OsSchedTaskWait(),需要2個參數:LOS_DL_LIST *list是互斥鎖等資源的阻塞鏈表,阻塞的任務會掛這個鏈表里;UINT32 ticks是任務阻塞的時間。分析下具體代碼:

⑴獲取正在請求互斥鎖等資源的當前任務,⑵設置任務狀態為阻塞狀態。⑶把任務插入互斥鎖等資源的阻塞鏈表的尾部。⑷如果不是永久阻塞等待,任務的狀態還需要設置為:

  1. VOID OsSchedTaskWait(LOS_DL_LIST *list, UINT32 ticks) 
  2. ⑴  LosTaskCB *runTask = g_losTask.runTask; 
  3.  
  4. ⑵  runTask->taskStatus |= OS_TASK_STATUS_PEND; 
  5. ⑶  LOS_ListTailInsert(list, &runTask->pendList); 
  6.  
  7.     if (ticks != LOS_WAIT_FOREVER) { 
  8. ⑷      runTask->taskStatus |= OS_TASK_STATUS_PEND_TIME; 
  9.         runTask->waitTimes = ticks; 
  10.     } 

 3.5.2 任務喚醒

我們分析下任務喚醒的函數OsSchedTaskWake(),需要1個參數:LosTaskCB *resumedTask是需要喚醒的任務;任務喚醒函數會從阻塞鏈表里刪除并加入就緒隊列,下面分析下具體代碼:

⑴把要喚醒的任務從所在的阻塞隊列中刪除,然后更改狀態不再為阻塞狀態。⑵如果任務不是永久等待,需要從定時器排序鏈表中刪除,并設置狀態不再是等待超時。⑶如果任務是阻塞狀態,改為就緒狀態并加入就緒隊列。

  1. VOID OsSchedTaskWake(LosTaskCB *resumedTask) 
  2. ⑴  LOS_ListDelete(&resumedTask->pendList); 
  3.     resumedTask->taskStatus &= ~OS_TASK_STATUS_PEND; 
  4.  
  5. ⑵  if (resumedTask->taskStatus & OS_TASK_STATUS_PEND_TIME) { 
  6.         OsDeleteSortLink(&resumedTask->sortList, OS_SORT_LINK_TASK); 
  7.         resumedTask->taskStatus &= ~OS_TASK_STATUS_PEND_TIME; 
  8.     } 
  9.  
  10. ⑶  if (!(resumedTask->taskStatus & OS_TASK_STATUS_SUSPEND)) { 
  11.         OsSchedTaskEnQueue(resumedTask); 
  12.     } 

 小結

本文帶領大家一起剖析了鴻蒙輕內核任務模塊的源代碼,包含任務模塊的結構體,任務初始化過程源代碼,任務常用操作的源代碼。后續也會陸續推出更多的分享文章,敬請期待。

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

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

https://harmonyos.51cto.com

 

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

2021-05-20 09:50:20

鴻蒙HarmonyOS應用

2021-05-13 09:47:08

鴻蒙HarmonyOS應用

2021-05-12 09:45:20

鴻蒙HarmonyOS應用

2021-05-10 15:05:56

鴻蒙HarmonyOS應用

2021-06-04 09:57:49

鴻蒙HarmonyOS應用

2022-01-10 15:31:44

鴻蒙HarmonyOS應用

2022-01-12 10:50:23

鴻蒙HarmonyOS應用

2024-10-25 09:26:56

2021-10-20 16:08:57

鴻蒙HarmonyOS應用

2021-05-25 09:28:34

鴻蒙HarmonyOS應用

2021-06-04 14:15:10

鴻蒙HarmonyOS應用

2021-05-17 09:28:59

鴻蒙HarmonyOS應用

2021-05-08 15:14:50

鴻蒙HarmonyOS應用

2021-05-31 20:30:55

鴻蒙HarmonyOS應用

2022-03-03 18:28:28

Harmony進程任務管理模塊

2022-04-13 11:02:12

鴻蒙事件模塊事件Event

2022-03-11 20:23:14

鴻蒙源碼分析進程管理

2021-05-11 09:54:55

鴻蒙HarmonyOS應用

2021-05-21 09:25:11

鴻蒙HarmonyOS應用

2021-06-09 09:48:01

鴻蒙HarmonyOS應用
點贊
收藏

51CTO技術棧公眾號

一本久久a久久免费精品不卡| 高清国产一区| 久久新电视剧免费观看| 国产v日韩v欧美v| 一区二区三区免费在线观看视频 | 国产激情欧美| 4444亚洲人成无码网在线观看| 精品久久久久久久久久久久久 | av二区在线| 国产麻花豆剧传媒精品mv在线| 国产一区二区三区网站| 欧美久久精品一级c片| 人人爽人人爽人人片| 欧美videossexotv100| 牛牛影视一区二区三区免费看| 激情深爱综合网| 亚洲国产一区二区三区青草影视| 麻豆电影在线播放| 国产免费观看高清视频| 在线看日本不卡| 亚洲欧美在线综合| 国产99在线 | 亚洲| 国产精品激情自拍| 国产精品美女久久久久aⅴ国产馆| 婷婷六月国产精品久久不卡| 美国黄色特级片| 91精品啪aⅴ在线观看国产| 亚洲女同女同女同女同女同69| 日韩免费在线电影| 国产在线成人精品午夜| 精品乱码一区二区三区| 一本到不卡免费一区二区| 第一av在线| chinese少妇国语对白| 欧美刺激午夜性久久久久久久| 婷婷亚洲图片| 无码人妻熟妇av又粗又大| 欧美视频1区| 色噜噜狠狠成人网p站| heyzo久久| 国产三级自拍视频| 菠萝蜜视频在线观看入口| 亚洲成年网站在线观看| 久久精品伊人| 色多多视频在线观看| 一级黄色片在线免费观看| 久久久亚洲精品视频| 久久久午夜精品| 亚洲精品福利| 欧美成人一区二区视频| 成人午夜精品久久久久久久蜜臀| 亚洲人成电影在线播放| 美女网站色91| 免费成人动漫| 伊人国产在线观看| 日本老太婆做爰视频| 亚洲视频在线免费观看| 国产suv精品一区二区三区| 视频91a欧美| 免费看污视频的网站| 日韩视频免费播放| 欧美激情免费在线| 亚洲欧洲综合另类在线| 国产精品久久久久久影院8一贰佰 国产精品久久久久久麻豆一区软件 | 性色一区二区三区| 日本精品600av| 中文字幕在线2021| 99视频精品全部免费看| 久久中文精品视频| 亚洲图片激情小说| 欧美大人香蕉在线| 日韩精品成人av| 在线看的片片片免费| 亚洲欧美成人一区| 色综合伊人色综合网| 国产精品丝袜在线| 亚洲深深色噜噜狠狠爱网站| 日本免费在线视频| 国产盗摄一区二区三区在线| 麻豆视频传媒入口| 国内成人精品视频| 91国产精品成人| 免费美女久久99| 福利视频一区| 国产v片在线观看| 人妻熟女aⅴ一区二区三区汇编| 久久综合九色综合网站| 亚洲欧洲一区二区三区在线观看 | 欧美人成在线视频| 亚洲综合网站在线观看| 日韩精品久久理论片| 日韩大尺度黄色| 精品国产免费无码久久久| 玖草视频在线观看| 天堂av在线中文| 欧美激情一级欧美精品| 91久久精品一区二区三区| 久久超级碰视频| 亚洲视频分类| 日本性爱视频在线观看| 在线观看日本视频| a级大片免费看| 亚洲最大色综合成人av| 色综合男人天堂| 91精品欧美一区二区三区综合在| www.在线成人| 99久久综合| 国产伊人久久| 国产乱理伦片a级在线观看| 国产精品99精品| 波多野结衣中文字幕在线播放| 欧美大香线蕉线伊人久久国产精品| 久久天天躁狠狠躁夜夜爽蜜月| 色综合网色综合| 久久久一区二区三区捆绑**| 亚洲激情综合| 欧美交a欧美精品喷水| 欧美午夜大胆人体| www.xxxx国产| 国产一级片网址| 中国xxxx性xxxx产国| 中文字幕无码精品亚洲资源网久久| 国产专区精品视频| 精品国产一区av| 欧美久久久久中文字幕| 亚洲免费资源在线播放| 激情伊人五月天久久综合| 久久精品国产68国产精品亚洲| 国产精品扒开腿做爽爽爽视频软件| 欧美色视频免费| 一级一片免费看| 久久福利免费视频| 一个人看的视频www| 国产肥臀一区二区福利视频| 国外成人在线视频网站| 国产激情999| 日韩视频欧美视频| 精品国产免费人成电影在线观看四季| 在线观看视频免费一区二区三区| 成年人在线看| 国产乱叫456在线| 毛片在线免费视频| 2017亚洲天堂| wwwwxxxx国产| 爱情岛论坛亚洲自拍| www.超碰com| 国产 欧美 日韩 一区| 久久精品日产第一区二区三区乱码 | 又大又长粗又爽又黄少妇视频| 日韩国产一级片| 亚洲一区二区三区涩| 国产精品一区二区在线观看| 国产美女主播一区| 青青在线视频一区二区三区| 精品国产视频在线| 中文字幕亚洲自拍| 亚洲精品综合精品自拍| 亚洲风情亚aⅴ在线发布| 欧美精品在线观看一区二区| 欧美a级片网站| 偷拍一区二区| 色综合久久中文| 精品国产影院| 牛牛影视一区二区三区免费看| avtt久久| xxxxxhd亚洲人hd| 粉嫩久久久久久久极品| 99国产精品免费网站| 超碰在线成人| 成人性生交大片免费看96| 婷婷综合国产| 成人动态视频| 日本欧美三级| 国产一区二区观看| 成人毛片在线| 亚洲最新色图| 亚洲激情黄色| 日韩av一级片| 国产麻豆精品theporn| 国产高清一区日本| eeuss影院一区二区三区| 97超碰欧美中文字幕| 久久亚洲私人国产精品va媚药| av在线这里只有精品| 97久久精品人人做人人爽| 成人综合婷婷国产精品久久免费| 成人免费视频一区| 欧美韩国日本综合| 亚洲少妇最新在线视频| 免播放器亚洲| 中文视频一区| 日韩一级在线| 国产一区二区三区不卡在线观看| 国内精品在线播放| 91日韩在线专区| 中文字幕一区二区视频| 亚洲国产经典视频| 一区二区三区精品视频| 欧美视频二区36p| 欧美日本乱大交xxxxx| 日韩一区二区在线看| 国产丝袜一区二区三区免费视频| 国产午夜精品一区理论片飘花| 日韩在线观看免费全集电视剧网站| 久久99青青精品免费观看| 国产97免费视| 国产日韩久久| 少妇久久久久久被弄到高潮| 18禁男女爽爽爽午夜网站免费| 欧美日韩一区二区三区69堂| 99精品一区二区三区无码吞精| 一级在线观看视频| 日日摸天天添天天添破| 性欧美8khd高清极品| av午夜在线| 成人日韩在线观看| 亚洲肉体裸体xxxx137| 亚洲高清二区| 成人免费高清在线| 亚洲大片在线观看| 欧美成人福利视频| 久久综合五月天| 91精品久久久久久久久青青 | 亚洲福利在线观看| 国产午夜精品理论片a级大结局| 亚洲第一福利一区| 精品国产污污免费网站入口| 日韩亚洲精品视频| 5566av亚洲| 欧美日韩在线一| 大地资源二中文在线影视观看| 丁香六月婷婷综合| 成人三级黄色免费网站| 欧洲精品一区二区三区| 三区四区不卡| 国产成人精品午夜视频免费| 亚洲国产欧美在线| 亚洲国产精品大全| 国产精品人成电影在线观看| 亚洲欧美日韩另类精品一区二区三区 | 欧美视频亚洲图片| 免费看一级一片| 性做久久久久久久| 日韩中文视频| 一本到12不卡视频在线dvd| 国产精品自在在线| 狠狠色狠狠色综合日日小说| 亚洲人av在线影院| 91在线观看免费高清完整版在线观看| av一区二区三区免费观看| 毛茸茸free性熟hd| a网站在线观看| 欧美日韩在线精品一区二区三区激情综合 | 欧美性一级生活| 欧美激情乱人伦一区| 日韩一区不卡| 亚洲av无码一区二区二三区| 国产乱码精品一区二三区蜜臂| 精品人人视频| 欧美色123| 中文字幕在线不卡视频| 亚洲午夜av电影| 精品久久久久久一区二区里番| 久久精品.com| 国产成人自拍视频在线| 欧美女同一区| 欧美va天堂在线| 国产亚洲欧洲997久久综合| 日韩成人中文字幕| 国产精品日韩一区二区三区 | www.av日韩| 6080成人| 成人激情校园春色| 精品国产百合女同互慰| 91久久久久久久| 色婷婷一区二区三区在线观看| 最近中文字幕在线观看| 日韩免费电影| 日本人妖一区二区| 69久久99精品久久久久婷婷| 国产精品自拍偷拍| 亚洲精品在线视频播放| 亚洲国产精品久久久久久6q| 人人九九精品视频| 成人精品免费视频| 亚洲色图色老头| 亚洲精品720p| 美日韩免费视频| 中文乱码字幕高清一区二区| 18+激情视频在线| 日韩一区二区免费看| 欧美丝袜一区二区| 国产欧美精品在线播放| 色呦呦一区二区| 8888四色奇米在线观看| 亚洲午夜精品一区二区国产| 亚洲在线观看免费| 久久免费视频这里只有精品| 免费日韩视频在线观看| 国产黄色小视频在线观看| 亚洲va久久| 亚洲欧美日韩电影| 日本不卡视频在线播放| 亚洲911精品成人18网站| 四虎在线免费看| 性色一区二区| 欧美日韩美女在线观看| 欧美中在线观看| 成年人观看网站| 奴色虐av一区二区三区| 久久久成人av毛片免费观看| 视频一区视频二区在线观看| 欧美亚洲图片小说| 久久男人的天堂| 穿情趣内衣被c到高潮视频| 欧美双性人妖o0| 国产区视频在线| 亚洲一区免费| 欧美成人r级一区二区三区| 蜜桃999成人看片在线观看| 亚洲激情视频一区| xxxx日韩| 色综合天天综合网天天看片| 欧美日韩亚洲在线| www.亚洲激情| 色婷婷在线观看视频| 久久97久久97精品免视看秋霞| 亚洲日本韩国一区| 成人高清在线观看| 国产精品视频一区二区三| 91成人福利社区| 欧洲人成人精品| 久久66热这里只有精品| 久久精品老司机| 亚洲黄色中文字幕| 97aⅴ精品视频一二三区| 国产精品香蕉在线观看| 欧洲av无码放荡人妇网站| 亚洲精品视频网| 国自产拍偷拍福利精品免费一| 欧美日韩裸体免费视频| 国产精品久久久久久久久久小说| 久久婷婷五月综合| 亚洲一区二区三区中文字幕在线观看 | 免费国产自线拍一欧美视频| 一区二区三区视频在线| 一区二区三区四区毛片| jzzjzzjzz亚洲成熟少妇| 欧美成人中文| 日韩精品视频免费专区在线播放| 日韩欧美视频网站| 青青青草网站免费视频在线观看| 在线一区免费观看| 美女扒开尿口让男人操亚洲视频网站| 亚洲中文字幕无码一区| 电影亚洲一区| 狠狠躁夜夜躁人人爽超碰91| 亚洲欧美国产不卡| 飘雪影视在线观看免费观看| 奇米在线7777在线精品| 欧美zozo另类异族| 日韩av一二三四区| 麻豆av在线免费看| 不卡的av电影| 亚洲一区亚洲二区| 亚洲免费视频二区| 免费亚洲电影| 91麻豆免费视频| 国产青春久久久国产毛片| 日本韩国欧美中文字幕| 欧美区国产区| 日韩在线观看高清| 国产精品免费无码| 神马午夜久久| 精品小视频在线| 免费在线观看成年人视频| 黑色丝袜福利片av久久| 538prom精品视频线放| 欧美日韩在线观看不卡| gogo亚洲高清大胆美女人体| 红桃视频成人在线观看| 国产精品入口芒果| 在线看片福利| 欧美日韩午夜精品| 国产精品一区二区小说| av成人免费看| 欧美一卡二卡三卡| 国产chinesehd精品露脸| 秋霞国产精品| 日韩精品一区二区三区视频播放 | 免费在线性爱视频| 91蝌蚪porny| 免费看av软件| 奇米777日韩| 精品成人免费观看| 99在线视频免费| 国产字幕视频一区二区| 久久噜噜噜精品国产亚洲综合| 久久中文字幕免费| 日韩精品一二三四|