鸿蒙轻内核M核源码分析系列十三(续) 消息队列QueueMail接口

开发 前端
之前分析过队列(Queue)的源代码,了解了队列初始化、队列创建、删除、队列读取写入等操作。队列还提供了两个接口OsQueueMailAlloc和OsQueueMailFree。

[[425060]]

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

之前分析过队列(Queue)的源代码,了解了队列初始化、队列创建、删除、队列读取写入等操作。队列还提供了两个接口OsQueueMailAlloc和OsQueueMailFree。队列可以和一个静态内存池关联起来,一个任务从静态内存池申请内存块时,如果申请不到,会把该任务插入到队列的内存阻塞链表中,等有其他任务释放内存时,该任务会被分配内存块。

接下来,详细看下这2个接口的源代码。

1、队列结构体定义

1.1 队列结构体定义

我们回忆下队列结构体的定义,在文件kernel\include\los_queue.h中定义队列控制块结构体为LosQueueCB,结构体源代码如下。需要看下成员变量memList,当任务从和队列关联的静态内存池中申请不到空闲内存块时,会把任务插入memList内存阻塞链表,然后调度,进行任务切换。等有其他任务释放空闲内存块到这个静态内存池时,该任务申请到空闲内存块,并把任务从memList内存阻塞链表移除,插入到任务就绪队列,并触发任务调度。

  1. typedef struct { 
  2.     UINT8 *queue;      /**< 队列内存空间的指针 */ 
  3.     UINT16 queueState; /**< 队列的使用状态 */ 
  4.     UINT16 queueLen;   /**< 队列长度,即消息数量 */ 
  5.     UINT16 queueSize;  /**< 消息节点大小 */ 
  6.     UINT16 queueID;    /**< 队列编号  */ 
  7.     UINT16 queueHead;  /**< 消息头节点位置 */ 
  8.     UINT16 queueTail;  /**< 消息尾节点位置 */ 
  9.     UINT16 readWriteableCnt[OS_READWRITE_LEN]; /**< 2维数组,可读、可写的消息数量, 0:可读, 1:可写 */ 
  10.     LOS_DL_LIST readWriteList[OS_READWRITE_LEN]; /**< 2维双向链表数组,阻塞读、写任务的双向链表, 0:读链表, 1:写链表 */ 
  11.     LOS_DL_LIST memList; /**< 内存节点双向链表 */ 
  12. } LosQueueCB; 

2、QueueMail接口源码分析

2.1 OsQueueMailAlloc接口

我们可以使用函数VOID *OsQueueMailAlloc(UINT32 queueID, VOID *mailPool, UINT32 timeOut)从和队列关联的静态内存池中申请空闲内存,下面通过分析源码看看如何申请内存。该函数需要3个参数,queueID是一个在使用状态的队列的编号,*mailPool是和队列关联的静态内存池地址,timeOut是超时时间,取值[0,LOS_WAIT_FOREVER]。该接口函数返回申请到的内存地址或者NULL。

⑴处开始对参数进行校验,⑵处根据队列编号获取队列控制结构体queueCB,然后校验该队列是否为使用状态。⑶处调用静态内存分配函数LOS_MemboxAlloc获取空闲内存块,然后获取的内存地址不为NULL,返回该内存块地址,否则执行后续代码。⑷处获取当前运行的任务控制结构体,⑸处把当前任务加入队列的内存阻塞链表queueCB->memList,然后触发任务调度。

等有其他其他任务调用OsQueueMailFree释放内存后,上述阻塞的任务获得内存块,或者因超时退出阻塞列表并调度运行后,会开始执行⑹处语句。⑺处表示因为超时返回,任务没有获取到内存块,跳转到END标签,返回NULL内存地址。⑻处表示获取到内存块,把任务的msg置空,并返回获取到的内存块的地址。

  1. LITE_OS_SEC_TEXT VOID *OsQueueMailAlloc(UINT32 queueID, VOID *mailPool, UINT32 timeOut) 
  2.     VOID *mem = (VOID *)NULL
  3.     UINT32 intSave; 
  4.     LosQueueCB *queueCB = (LosQueueCB *)NULL
  5.     LosTaskCB *runTsk = (LosTaskCB *)NULL
  6.  
  7. ⑴  if (queueID >= LOSCFG_BASE_IPC_QUEUE_LIMIT) { 
  8.         return NULL
  9.     } 
  10.  
  11.     if (mailPool == NULL) { 
  12.         return NULL
  13.     } 
  14.  
  15.     if (timeOut != LOS_NO_WAIT) { 
  16.         if (OS_INT_ACTIVE) { 
  17.             return NULL
  18.         } 
  19.     } 
  20.  
  21.     intSave = LOS_IntLock(); 
  22. ⑵  queueCB = GET_QUEUE_HANDLE(queueID); 
  23.     if (queueCB->queueState == OS_QUEUE_UNUSED) { 
  24.         goto END
  25.     } 
  26.  
  27. ⑶  mem = LOS_MemboxAlloc(mailPool); 
  28.     if (mem == NULL) { 
  29.         if (timeOut == LOS_NO_WAIT) { 
  30.             goto END
  31.         } 
  32.  
  33. ⑷      runTsk = (LosTaskCB *)g_losTask.runTask; 
  34. ⑸      OsSchedTaskWait(&queueCB->memList, timeOut); 
  35.         LOS_IntRestore(intSave); 
  36.         LOS_Schedule(); 
  37.  
  38. ⑹      intSave = LOS_IntLock(); 
  39.         if (runTsk->taskStatus & OS_TASK_STATUS_TIMEOUT) { 
  40. ⑺          runTsk->taskStatus &= (~OS_TASK_STATUS_TIMEOUT); 
  41.             goto END
  42.         } else { 
  43.             /* When enters the current branch, means the current task already got a available membox, 
  44.              * so the runTsk->msg can not be NULL
  45.              */ 
  46. ⑻          mem = runTsk->msg; 
  47.             runTsk->msg = NULL
  48.         } 
  49.     } 
  50.  
  51. END
  52.     LOS_IntRestore(intSave); 
  53.     return mem; 

2.2 OsQueueMailFree

我们可以使用函数UINT32 OsQueueMailFree(UINT32 queueID, VOID *mailPool, VOID *mailMem)释放空闲内存到和队列关联的静态内存池中,下面通过分析源码看看如何释放内存。该函数需要3个参数,queueID是一个在使用状态的队列的编号,*mailPool是和队列关联的静态内存池地址,*mailMem表示要释放的内存块地址。该接口返回值类型为无符号整数,表示是否成功或者错误码。

⑴处开始对参数进行校验。⑵处调用静态内存释放函数LOS_MemboxFree释放空闲内存块,如果释放失败,返回错误码。⑶处根据队列编号获取队列控制结构体queueCB,然后校验该队列是否为使用状态。成功释放内存后,如果队列的内存阻塞列表不为空,有阻塞任务,则执行⑷。⑸处从阻塞列表中获取第一个任务控制结构体,然后调用接口OsSchedTaskWake把任务从阻塞列表移除,并添加到任务就绪队列。⑹处从静态内存池申请一个内存块,如果申请失败返回错误码,否则执行⑺,把申请到的内存赋值到任务控制结构体的msg成员变量,然后触发调度。

  1. LITE_OS_SEC_TEXT UINT32 OsQueueMailFree(UINT32 queueID, VOID *mailPool, VOID *mailMem) 
  2.     VOID *mem = (VOID *)NULL
  3.     UINT32 intSave; 
  4.     LosQueueCB *queueCB = (LosQueueCB *)NULL
  5.     LosTaskCB *resumedTask = (LosTaskCB *)NULL
  6.  
  7. ⑴  if (queueID >= LOSCFG_BASE_IPC_QUEUE_LIMIT) { 
  8.         return LOS_ERRNO_QUEUE_MAIL_HANDLE_INVALID; 
  9.     } 
  10.  
  11.     if (mailPool == NULL) { 
  12.         return LOS_ERRNO_QUEUE_MAIL_PTR_INVALID; 
  13.     } 
  14.  
  15.     intSave = LOS_IntLock(); 
  16.  
  17. ⑵  if (LOS_MemboxFree(mailPool, mailMem)) { 
  18.         LOS_IntRestore(intSave); 
  19.         return LOS_ERRNO_QUEUE_MAIL_FREE_ERROR; 
  20.     } 
  21.  
  22. ⑶  queueCB = GET_QUEUE_HANDLE(queueID); 
  23.     if (queueCB->queueState == OS_QUEUE_UNUSED) { 
  24.         LOS_IntRestore(intSave); 
  25.         return LOS_ERRNO_QUEUE_NOT_CREATE; 
  26.     } 
  27.  
  28. ⑷  if (!LOS_ListEmpty(&queueCB->memList)) { 
  29. ⑸      resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&queueCB->memList)); 
  30.         OsSchedTaskWake(resumedTask); 
  31. ⑹      mem = LOS_MemboxAlloc(mailPool); 
  32.         if (mem == NULL) { 
  33.             LOS_IntRestore(intSave); 
  34.             return LOS_ERRNO_QUEUE_NO_MEMORY; 
  35.         } 
  36. ⑺      resumedTask->msg = mem; 
  37.         LOS_IntRestore(intSave); 
  38.         LOS_Schedule(); 
  39.     } else { 
  40.         LOS_IntRestore(intSave); 
  41.     } 
  42.     return LOS_OK; 

小结

本文带领大家一起剖析了鸿蒙轻内核的队列模块的QueueMail两个接口的源代码。

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2021-06-04 14:15:10

鸿蒙HarmonyOS应用

2021-06-04 09:57:49

鸿蒙HarmonyOS应用

2022-01-12 10:50:23

鸿蒙HarmonyOS应用

2022-01-10 15:31:44

鸿蒙HarmonyOS应用

2021-05-12 09:45:20

鸿蒙HarmonyOS应用

2021-10-20 16:08:57

鸿蒙HarmonyOS应用

2021-05-25 09:28:34

鸿蒙HarmonyOS应用

2021-05-17 09:28:59

鸿蒙HarmonyOS应用

2021-05-08 15:14:50

鸿蒙HarmonyOS应用

2021-05-31 20:30:55

鸿蒙HarmonyOS应用

2021-05-21 09:25:11

鸿蒙HarmonyOS应用

2021-06-09 09:48:01

鸿蒙HarmonyOS应用

2021-05-27 09:43:56

鸿蒙HarmonyOS应用

2021-05-11 09:54:55

鸿蒙HarmonyOS应用

2022-04-13 11:02:12

鸿蒙事件模块事件Event

2022-03-03 18:28:28

Harmony进程任务管理模块

2022-03-11 20:23:14

鸿蒙源码分析进程管理

2021-07-06 09:45:03

鸿蒙HarmonyOS应用

2021-04-30 15:06:34

鸿蒙HarmonyOS应用

2022-01-14 08:39:47

鸿蒙HarmonyOS应用
点赞
收藏

51CTO技术栈公众号