更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
los_queue.c
浏览该文件的文档.
1/**
2 * @file los_queue.c
3 * @brief
4 * @verbatim
5 基本概念
6 队列又称消息队列,是一种常用于任务间通信的数据结构。队列接收来自任务或中断的
7 不固定长度消息,并根据不同的接口确定传递的消息是否存放在队列空间中。
8
9 任务能够从队列里面读取消息,当队列中的消息为空时,挂起读取任务;当队列中有新消息时,
10 挂起的读取任务被唤醒并处理新消息。任务也能够往队列里写入消息,当队列已经写满消息时,
11 挂起写入任务;当队列中有空闲消息节点时,挂起的写入任务被唤醒并写入消息。如果将
12 读队列和写队列的超时时间设置为0,则不会挂起任务,接口会直接返回,这就是非阻塞模式。
13
14 消息队列提供了异步处理机制,允许将一个消息放入队列,但不立即处理。同时队列还有缓冲消息的作用。
15
16 队列特性
17 消息以先进先出的方式排队,支持异步读写。
18 读队列和写队列都支持超时机制。
19 每读取一条消息,就会将该消息节点设置为空闲。
20 发送消息类型由通信双方约定,可以允许不同长度(不超过队列的消息节点大小)的消息。
21 一个任务能够从任意一个消息队列接收和发送消息。
22 多个任务能够从同一个消息队列接收和发送消息。
23 创建队列时所需的队列空间,默认支持接口内系统自行动态申请内存的方式,同时也支持将用户分配的队列空间作为接口入参传入的方式。
24
25 队列运作原理
26 创建队列时,创建队列成功会返回队列ID。
27
28 在队列控制块中维护着一个消息头节点位置Head和一个消息尾节点位置Tail来,用于表示当前
29 队列中消息的存储情况。Head表示队列中被占用的消息节点的起始位置。Tail表示被占用的
30 消息节点的结束位置,也是空闲消息节点的起始位置。队列刚创建时,Head和Tail均指向队列起始位置。
31
32 写队列时,根据readWriteableCnt[1]判断队列是否可以写入,不能对已满(readWriteableCnt[1]为0)
33 队列进行写操作。写队列支持两种写入方式:向队列尾节点写入,也可以向队列头节点写入。尾节点写入时,
34 根据Tail找到起始空闲消息节点作为数据写入对象,如果Tail已经指向队列尾部则采用回卷方式。头节点写入时,
35 将Head的前一个节点作为数据写入对象,如果Head指向队列起始位置则采用回卷方式。
36
37 读队列时,根据readWriteableCnt[0]判断队列是否有消息需要读取,对全部空闲(readWriteableCnt[0]为0)
38 队列进行读操作会引起任务挂起。如果队列可以读取消息,则根据Head找到最先写入队列的消息节点进行读取。
39 如果Head已经指向队列尾部则采用回卷方式。
40
41 删除队列时,根据队列ID找到对应队列,把队列状态置为未使用,把队列控制块置为初始状态。
42 如果是通过系统动态申请内存方式创建的队列,还会释放队列所占内存。
43
44 使用场景
45 队列用于任务间通信,可以实现消息的异步处理。同时消息的发送方和接收方不需要彼此联系,两者间是解耦的。
46
47 队列错误码
48 对存在失败可能性的操作返回对应的错误码,以便快速定位错误原因。
49 * @endverbatim
50 */
51
52
53/*
54 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
55 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
56 *
57 * Redistribution and use in source and binary forms, with or without modification,
58 * are permitted provided that the following conditions are met:
59 *
60 * 1. Redistributions of source code must retain the above copyright notice, this list of
61 * conditions and the following disclaimer.
62 *
63 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
64 * of conditions and the following disclaimer in the documentation and/or other materials
65 * provided with the distribution.
66 *
67 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
68 * to endorse or promote products derived from this software without specific prior written
69 * permission.
70 *
71 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
72 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
73 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
74 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
75 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
76 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
77 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
78 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
79 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
80 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
81 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
82 */
83
84#include "los_queue_pri.h"
85#include "los_queue_debug_pri.h"
86#include "los_task_pri.h"
87#include "los_sched_pri.h"
88#include "los_spinlock.h"
89#include "los_mp.h"
90#include "los_percpu_pri.h"
91#include "los_hook.h"
92
93#ifdef LOSCFG_BASE_IPC_QUEUE
94#if (LOSCFG_BASE_IPC_QUEUE_LIMIT <= 0)
95#error "queue maxnum cannot be zero"
96#endif /* LOSCFG_BASE_IPC_QUEUE_LIMIT <= 0 */
97
98LITE_OS_SEC_BSS LosQueueCB *g_allQueue = NULL;///< 消息队列池
99LITE_OS_SEC_BSS STATIC LOS_DL_LIST g_freeQueueList;///< 空闲队列链表,管分配的,需要队列从这里申请
100
101/*
102 * Description : queue initial | 消息队列模块初始化
103 * Return : LOS_OK on success or error code on failure
104 */
105LITE_OS_SEC_TEXT_INIT UINT32 OsQueueInit(VOID)
106{
107 LosQueueCB *queueNode = NULL;
108 UINT32 index;
109 UINT32 size;
110
111 size = LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(LosQueueCB);//支持1024个IPC队列
112 /* system resident memory, don't free */
113 g_allQueue = (LosQueueCB *)LOS_MemAlloc(m_aucSysMem0, size);//常驻内存
114 if (g_allQueue == NULL) {
115 return LOS_ERRNO_QUEUE_NO_MEMORY;
116 }
117 (VOID)memset_s(g_allQueue, size, 0, size);//清0
118 LOS_ListInit(&g_freeQueueList);//初始化空闲链表
119 for (index = 0; index < LOSCFG_BASE_IPC_QUEUE_LIMIT; index++) {//循环初始化每个消息队列
120 queueNode = ((LosQueueCB *)g_allQueue) + index;//一个一个来
121 queueNode->queueID = index;//这可是 队列的身份证
122 LOS_ListTailInsert(&g_freeQueueList, &queueNode->readWriteList[OS_QUEUE_WRITE]);//通过写节点挂到空闲队列链表上
123 }//这里要注意是用 readWriteList 挂到 g_freeQueueList链上的,所以要通过 GET_QUEUE_LIST 来找到 LosQueueCB
124
125 if (OsQueueDbgInitHook() != LOS_OK) {//调试队列使用的.
126 return LOS_ERRNO_QUEUE_NO_MEMORY;
127 }
128 return LOS_OK;
129}
130///创建一个队列,根据用户传入队列长度和消息节点大小来开辟相应的内存空间以供该队列使用,参数queueID带走队列ID
131LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueCreate(CHAR *queueName, UINT16 len, UINT32 *queueID,
132 UINT32 flags, UINT16 maxMsgSize)
133{
134 LosQueueCB *queueCB = NULL;
135 UINT32 intSave;
136 LOS_DL_LIST *unusedQueue = NULL;
137 UINT8 *queue = NULL;
138 UINT16 msgSize;
139
140 (VOID)queueName;
141 (VOID)flags;
142
143 if (queueID == NULL) {
144 return LOS_ERRNO_QUEUE_CREAT_PTR_NULL;
145 }
146
147 if (maxMsgSize > (OS_NULL_SHORT - sizeof(UINT32))) {// maxMsgSize上限 为啥要减去 sizeof(UINT32) ,因为前面存的是队列的大小
148 return LOS_ERRNO_QUEUE_SIZE_TOO_BIG;
149 }
150
151 if ((len == 0) || (maxMsgSize == 0)) {
152 return LOS_ERRNO_QUEUE_PARA_ISZERO;
153 }
154
155 msgSize = maxMsgSize + sizeof(UINT32);//总size = 消息体内容长度 + 消息大小(UINT32)
156 /*
157 * Memory allocation is time-consuming, to shorten the time of disable interrupt,
158 * move the memory allocation to here.
159 *///内存分配非常耗时,为了缩短禁用中断的时间,将内存分配移到此处,用的时候分配队列内存
160 queue = (UINT8 *)LOS_MemAlloc(m_aucSysMem1, (UINT32)len * msgSize);//从系统内存池中分配,由这里提供读写队列的内存
161 if (queue == NULL) {//这里是一次把队列要用到的所有最大内存都申请下来了,能保证不会出现后续使用过程中内存不够的问题出现
162 return LOS_ERRNO_QUEUE_CREATE_NO_MEMORY;//调用处有 OsSwtmrInit sys_mbox_new DoMqueueCreate ==
163 }
164
165 SCHEDULER_LOCK(intSave);
166 if (LOS_ListEmpty(&g_freeQueueList)) {//没有空余的队列ID的处理,注意软时钟定时器是由 g_swtmrCBArray统一管理的,里面有正在使用和可分配空闲的队列
167 SCHEDULER_UNLOCK(intSave);//g_freeQueueList是管理可用于分配的队列链表,申请消息队列的ID需要向它要
169 (VOID)LOS_MemFree(m_aucSysMem1, queue);//没有就要释放 queue申请的内存
170 return LOS_ERRNO_QUEUE_CB_UNAVAILABLE;
171 }
172
173 unusedQueue = LOS_DL_LIST_FIRST(&g_freeQueueList);//找到一个没有被使用的队列
174 LOS_ListDelete(unusedQueue);//将自己从g_freeQueueList中摘除, unusedQueue只是个 LOS_DL_LIST 结点.
175 queueCB = GET_QUEUE_LIST(unusedQueue);//通过unusedQueue找到整个消息队列(LosQueueCB)
176 queueCB->queueLen = len; //队列中消息的总个数,注意这个一旦创建是不能变的.
177 queueCB->queueSize = msgSize;//消息节点的大小,注意这个一旦创建也是不能变的.
178 queueCB->queueHandle = queue; //队列句柄,队列内容存储区.
179 queueCB->queueState = OS_QUEUE_INUSED; //队列状态使用中
180 queueCB->readWriteableCnt[OS_QUEUE_READ] = 0;//可读资源计数,OS_QUEUE_READ(0):可读.
181 queueCB->readWriteableCnt[OS_QUEUE_WRITE] = len;//可些资源计数 OS_QUEUE_WRITE(1):可写, 默认len可写.
182 queueCB->queueHead = 0;//队列头节点
183 queueCB->queueTail = 0;//队列尾节点
184 LOS_ListInit(&queueCB->readWriteList[OS_QUEUE_READ]);//初始化可读队列任务链表
185 LOS_ListInit(&queueCB->readWriteList[OS_QUEUE_WRITE]);//初始化可写队列任务链表
186 LOS_ListInit(&queueCB->memList);//
187
188 OsQueueDbgUpdateHook(queueCB->queueID, OsCurrTaskGet()->taskEntry);//在创建或删除队列调试信息时更新任务条目
189 SCHEDULER_UNLOCK(intSave);
190
191 *queueID = queueCB->queueID;//带走队列ID
192 OsHookCall(LOS_HOOK_TYPE_QUEUE_CREATE, queueCB);
193 return LOS_OK;
194}
195///读队列参数检查
196STATIC LITE_OS_SEC_TEXT UINT32 OsQueueReadParameterCheck(UINT32 queueID, const VOID *bufferAddr,
197 const UINT32 *bufferSize, UINT32 timeout)
198{
199 if (GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {//队列ID不能超上限
200 return LOS_ERRNO_QUEUE_INVALID;
201 }
202 if ((bufferAddr == NULL) || (bufferSize == NULL)) {//缓存地址和大小参数判断
203 return LOS_ERRNO_QUEUE_READ_PTR_NULL;
204 }
205
206 if ((*bufferSize == 0) || (*bufferSize > (OS_NULL_SHORT - sizeof(UINT32)))) {//限制了读取数据的上限64K, sizeof(UINT32)代表的是队列的长度
207 return LOS_ERRNO_QUEUE_READSIZE_IS_INVALID; //所以要减去
208 }
209
211
212 if (timeout != LOS_NO_WAIT) {//等待一定时间再读取
213 if (OS_INT_ACTIVE) {//如果碰上了硬中断
214 return LOS_ERRNO_QUEUE_READ_IN_INTERRUPT;//意思是:硬中断发生时是不能读消息队列的
215 }
216 }
217 return LOS_OK;
218}
219///写队列参数检查
220STATIC LITE_OS_SEC_TEXT UINT32 OsQueueWriteParameterCheck(UINT32 queueID, const VOID *bufferAddr,
221 const UINT32 *bufferSize, UINT32 timeout)
222{
223 if (GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {//队列ID不能超上限
224 return LOS_ERRNO_QUEUE_INVALID;
225 }
226
227 if (bufferAddr == NULL) {//没有数据源
228 return LOS_ERRNO_QUEUE_WRITE_PTR_NULL;
229 }
230
231 if (*bufferSize == 0) {//这里没有限制写队列的大小,如果写入一个很大buf 会怎样?
232 return LOS_ERRNO_QUEUE_WRITESIZE_ISZERO;
233 }
234
236
237 if (timeout != LOS_NO_WAIT) {
238 if (OS_INT_ACTIVE) {
239 return LOS_ERRNO_QUEUE_WRITE_IN_INTERRUPT;
240 }
241 }
242 return LOS_OK;
243}
244///队列buf操作,注意队列数据是按顺序来读取的,要不从头,要不从尾部,不会出现从中间读写,所有可由 head 和 tail 来管理队列.
245STATIC VOID OsQueueBufferOperate(LosQueueCB *queueCB, UINT32 operateType, VOID *bufferAddr, UINT32 *bufferSize)
246{
247 UINT8 *queueNode = NULL;
248 UINT32 msgDataSize;
249 UINT16 queuePosition;
250
251 /* get the queue position | 先找到队列的位置*/
252 switch (OS_QUEUE_OPERATE_GET(operateType)) {//获取操作类型
253 case OS_QUEUE_READ_HEAD://从列队头开始读
254 queuePosition = queueCB->queueHead;//拿到头部位置
255 ((queueCB->queueHead + 1) == queueCB->queueLen) ? (queueCB->queueHead = 0) : (queueCB->queueHead++);//调整队列头部位置
256 break;
257 case OS_QUEUE_WRITE_HEAD://从列队头开始写
258 (queueCB->queueHead == 0) ? (queueCB->queueHead = queueCB->queueLen - 1) : (--queueCB->queueHead);//调整队列头部位置
259 queuePosition = queueCB->queueHead;//拿到头部位置
260 break;
261 case OS_QUEUE_WRITE_TAIL://从列队尾部开始写
262 queuePosition = queueCB->queueTail;//设置队列位置为尾部位置
263 ((queueCB->queueTail + 1) == queueCB->queueLen) ? (queueCB->queueTail = 0) : (queueCB->queueTail++);//调整队列尾部位置
264 break;
265 default: /* read tail, reserved. */
266 PRINT_ERR("invalid queue operate type!\n");
267 return;
268 }
269 //queueHandle是create队列时,由外界参数申请的一块内存. 用于copy 使用
270 queueNode = &(queueCB->queueHandle[(queuePosition * (queueCB->queueSize))]);//拿到队列节点
271
272 if (OS_QUEUE_IS_READ(operateType)) {//读操作处理,读队列分两步走
273 if (memcpy_s(&msgDataSize, sizeof(UINT32), queueNode + queueCB->queueSize - sizeof(UINT32),
274 sizeof(UINT32)) != EOK) {//1.先读出队列大小,由队列头四个字节表示
275 PRINT_ERR("get msgdatasize failed\n");
276 return;
277 }
278 msgDataSize = (*bufferSize < msgDataSize) ? *bufferSize : msgDataSize;
279 if (memcpy_s(bufferAddr, *bufferSize, queueNode, msgDataSize) != EOK) {//2.读表示读走已有数据,所以相当于bufferAddr接着了queueNode的数据
280 PRINT_ERR("copy message to buffer failed\n");
281 return;
282 }
283
284 *bufferSize = msgDataSize;//通过入参 带走消息的大小
285 } else {//只有读写两种操作,这里就是写队列了.写也分两步走 , @note_thinking 这里建议鸿蒙加上 OS_QUEUE_IS_WRITE 判断
286 if (memcpy_s(queueNode, queueCB->queueSize, bufferAddr, *bufferSize) != EOK) {//1.写入消息内容
287 PRINT_ERR("store message failed\n");//表示把外面数据写进来,所以相当于queueNode接着了bufferAddr的数据
288 return;
289 }
290 if (memcpy_s(queueNode + queueCB->queueSize - sizeof(UINT32), sizeof(UINT32), bufferSize,
291 sizeof(UINT32)) != EOK) {//2.写入消息数据的长度,sizeof(UINT32)
292 PRINT_ERR("store message size failed\n");
293 return;
294 }
295 }
296}
297///队列操作参数检查
298STATIC UINT32 OsQueueOperateParamCheck(const LosQueueCB *queueCB, UINT32 queueID,
299 UINT32 operateType, const UINT32 *bufferSize)
300{
301 if ((queueCB->queueID != queueID) || (queueCB->queueState == OS_QUEUE_UNUSED)) {//队列ID和状态判断
302 return LOS_ERRNO_QUEUE_NOT_CREATE;
303 }
304
305 if (OS_QUEUE_IS_WRITE(operateType) && (*bufferSize > (queueCB->queueSize - sizeof(UINT32)))) {//写时判断
306 return LOS_ERRNO_QUEUE_WRITE_SIZE_TOO_BIG;//塞进来的数据太大,大于队列节点能承受的范围
307 }
308 return LOS_OK;
309}
310
311/**
312 * @brief 队列操作.是读是写由operateType定
313 本函数是消息队列最重要的一个函数,可以分析出读取消息过程中
314 发生的细节,涉及任务的唤醒和阻塞,阻塞链表任务的相互提醒.
315 * @param queueID
316 * @param operateType
317 * @param bufferAddr
318 * @param bufferSize
319 * @param timeout
320 * @return UINT32
321 */
322UINT32 OsQueueOperate(UINT32 queueID, UINT32 operateType, VOID *bufferAddr, UINT32 *bufferSize, UINT32 timeout)
323{
324 UINT32 ret;
325 UINT32 readWrite = OS_QUEUE_READ_WRITE_GET(operateType);//获取读/写操作标识
326 UINT32 intSave;
327 OsHookCall(LOS_HOOK_TYPE_QUEUE_READ, (LosQueueCB *)GET_QUEUE_HANDLE(queueID), operateType, *bufferSize, timeout);
328
329 SCHEDULER_LOCK(intSave);
330 LosQueueCB *queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueID);//获取对应的队列控制块
331 ret = OsQueueOperateParamCheck(queueCB, queueID, operateType, bufferSize);//参数检查
332 if (ret != LOS_OK) {
333 goto QUEUE_END;
334 }
335
336 if (queueCB->readWriteableCnt[readWrite] == 0) {//根据readWriteableCnt判断队列是否有消息读/写
337 if (timeout == LOS_NO_WAIT) {//不等待直接退出
338 ret = OS_QUEUE_IS_READ(operateType) ? LOS_ERRNO_QUEUE_ISEMPTY : LOS_ERRNO_QUEUE_ISFULL;
339 goto QUEUE_END;
340 }
341
342 if (!OsPreemptableInSched()) {//不支持抢占式调度
343 ret = LOS_ERRNO_QUEUE_PEND_IN_LOCK;
344 goto QUEUE_END;
345 }
346 //任务等待,这里很重要啊,将自己从就绪列表摘除,让出了CPU并发起了调度,并挂在readWriteList[readWrite]上,挂的都等待读/写消息的task
347 LosTaskCB *runTask = OsCurrTaskGet();
348 OsTaskWaitSetPendMask(OS_TASK_WAIT_QUEUE, queueCB->queueID, timeout);
349 ret = runTask->ops->wait(runTask, &queueCB->readWriteList[readWrite], timeout);
350 if (ret == LOS_ERRNO_TSK_TIMEOUT) {//唤醒后如果超时了,返回读/写消息失败
351 ret = LOS_ERRNO_QUEUE_TIMEOUT;
352 goto QUEUE_END;//
353 }
354 } else {
355 queueCB->readWriteableCnt[readWrite]--;//对应队列中计数器--,说明一条消息只能被读/写一次
356 }
357
358 OsQueueBufferOperate(queueCB, operateType, bufferAddr, bufferSize);//发起读或写队列操作
359
360 if (!LOS_ListEmpty(&queueCB->readWriteList[!readWrite])) {//如果还有任务在排着队等待读/写入消息(当时不能读/写的原因有可能当时队列满了==)
361 LosTaskCB *resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&queueCB->readWriteList[!readWrite]));//取出要读/写消息的任务
362 OsTaskWakeClearPendMask(resumedTask);
363 resumedTask->ops->wake(resumedTask);
364 SCHEDULER_UNLOCK(intSave);
365 LOS_MpSchedule(OS_MP_CPU_ALL);//让所有CPU发出调度申请,因为很可能那个要读/写消息的队列是由其他CPU执行
366 LOS_Schedule();//申请调度
367 return LOS_OK;
368 } else {
369 queueCB->readWriteableCnt[!readWrite]++;//对应队列读/写中计数器++
370 }
371
372QUEUE_END:
373 SCHEDULER_UNLOCK(intSave);
374 return ret;
375}
376///接口函数定时读取消息队列
377LITE_OS_SEC_TEXT UINT32 LOS_QueueReadCopy(UINT32 queueID,
378 VOID *bufferAddr,
379 UINT32 *bufferSize,
380 UINT32 timeout)
381{
382 UINT32 ret;
383 UINT32 operateType;
384
385 ret = OsQueueReadParameterCheck(queueID, bufferAddr, bufferSize, timeout);//参数检查
386 if (ret != LOS_OK) {
387 return ret;
388 }
389
390 operateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_READ, OS_QUEUE_HEAD);//从头开始读
391 return OsQueueOperate(queueID, operateType, bufferAddr, bufferSize, timeout);//定时执行读操作
392}
393///接口函数从队列头开始写
394LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteHeadCopy(UINT32 queueID,
395 VOID *bufferAddr,
396 UINT32 bufferSize,
397 UINT32 timeout)
398{
399 UINT32 ret;
400 UINT32 operateType;
401
402 ret = OsQueueWriteParameterCheck(queueID, bufferAddr, &bufferSize, timeout);//参数检查
403 if (ret != LOS_OK) {
404 return ret;
405 }
406
407 operateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_WRITE, OS_QUEUE_HEAD);//从头开始写
408 return OsQueueOperate(queueID, operateType, bufferAddr, &bufferSize, timeout);//执行写操作
409}
410///接口函数 从队列尾部开始写
411LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteCopy(UINT32 queueID,
412 VOID *bufferAddr,
413 UINT32 bufferSize,
414 UINT32 timeout)
415{
416 UINT32 ret;
417 UINT32 operateType;
418
419 ret = OsQueueWriteParameterCheck(queueID, bufferAddr, &bufferSize, timeout);//参数检查
420 if (ret != LOS_OK) {
421 return ret;
422 }
423
424 operateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_WRITE, OS_QUEUE_TAIL);//从尾部开始写
425 return OsQueueOperate(queueID, operateType, bufferAddr, &bufferSize, timeout);//执行写操作
426}
427
428/**
429 * @brief
430 * @verbatim
431 外部接口 读一个队列数据
432 读队列时,根据Head找到最先写入队列中的消息节点进行读取。如果Head已经指向队列尾则采用回卷方式。
433 根据usReadableCnt判断队列是否有消息读取,对全部空闲(usReadableCnt为0)队列进行读队列操作会引起任务挂起。
434 * @endverbatim
435 */
436LITE_OS_SEC_TEXT UINT32 LOS_QueueRead(UINT32 queueID, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeout)
437{
438 return LOS_QueueReadCopy(queueID, bufferAddr, &bufferSize, timeout);
439}
440
441/**
442 * @brief
443 * @verbatim
444 外部接口 写一个队列数据
445 根据Tail找到被占用消息节点末尾的空闲节点作为数据写入对象。如果Tail已经指向队列尾则采用回卷方式。
446 根据usWritableCnt判断队列是否可以写入,不能对已满(usWritableCnt为0)队列进行写队列操作
447 * @endverbatim
448 */
449LITE_OS_SEC_TEXT UINT32 LOS_QueueWrite(UINT32 queueID, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeout)
450{
451 if (bufferAddr == NULL) {
452 return LOS_ERRNO_QUEUE_WRITE_PTR_NULL;
453 }
454 bufferSize = sizeof(CHAR *);
455 return LOS_QueueWriteCopy(queueID, &bufferAddr, bufferSize, timeout);
456}
457
458/**
459 * @brief
460 * @verbatim
461 外部接口 从头部写入
462 写队列时,根据Tail找到被占用消息节点末尾的空闲节点作为数据写入对象。如果Tail已经指向队列尾则采用回卷方式。
463 根据usWritableCnt判断队列是否可以写入,不能对已满(usWritableCnt为0)队列进行写队列操作
464 * @endverbatim
465 */
466LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteHead(UINT32 queueID,
467 VOID *bufferAddr,
468 UINT32 bufferSize,
469 UINT32 timeout)
470{
471 if (bufferAddr == NULL) {
472 return LOS_ERRNO_QUEUE_WRITE_PTR_NULL;
473 }
474 bufferSize = sizeof(CHAR *);
475 return LOS_QueueWriteHeadCopy(queueID, &bufferAddr, bufferSize, timeout);
476}
477
478/**
479 * @brief
480 * @verbatim
481 外部接口 删除队列,还有任务要读/写消息时不能删除
482 删除队列时,根据传入的队列ID寻找到对应的队列,把队列状态置为未使用,
483 释放原队列所占的空间,对应的队列控制头置为初始状态。
484 * @endverbatim
485 */
486LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueDelete(UINT32 queueID)
487{
488 LosQueueCB *queueCB = NULL;
489 UINT8 *queue = NULL;
490 UINT32 intSave;
491 UINT32 ret;
492
493 if (GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {
494 return LOS_ERRNO_QUEUE_NOT_FOUND;
495 }
496
497 SCHEDULER_LOCK(intSave);
498 queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueID);//拿到队列实体
499 if ((queueCB->queueID != queueID) || (queueCB->queueState == OS_QUEUE_UNUSED)) {
500 ret = LOS_ERRNO_QUEUE_NOT_CREATE;
501 goto QUEUE_END;
502 }
503
504 if (!LOS_ListEmpty(&queueCB->readWriteList[OS_QUEUE_READ])) {//尚有任务要读数据
505 ret = LOS_ERRNO_QUEUE_IN_TSKUSE;
506 goto QUEUE_END;
507 }
508
509 if (!LOS_ListEmpty(&queueCB->readWriteList[OS_QUEUE_WRITE])) {//尚有任务要写数据
510 ret = LOS_ERRNO_QUEUE_IN_TSKUSE;
511 goto QUEUE_END;
512 }
513
514 if (!LOS_ListEmpty(&queueCB->memList)) {//
515 ret = LOS_ERRNO_QUEUE_IN_TSKUSE;
516 goto QUEUE_END;
517 }
518
520 queueCB->queueLen) {//读写队列的内容长度不等于总长度
521 ret = LOS_ERRNO_QUEUE_IN_TSKWRITE;
522 goto QUEUE_END;
523 }
524
525 queue = queueCB->queueHandle; //队列buf
526 queueCB->queueHandle = NULL; //
527 queueCB->queueState = OS_QUEUE_UNUSED;//重置队列状态
528 queueCB->queueID = SET_QUEUE_ID(GET_QUEUE_COUNT(queueCB->queueID) + 1, GET_QUEUE_INDEX(queueCB->queueID));//@note_why 这里需要这样做吗?
529 OsQueueDbgUpdateHook(queueCB->queueID, NULL);
530
531 LOS_ListTailInsert(&g_freeQueueList, &queueCB->readWriteList[OS_QUEUE_WRITE]);//回收,将节点挂入可分配链表,等待重新被分配再利用
532 SCHEDULER_UNLOCK(intSave);
533 OsHookCall(LOS_HOOK_TYPE_QUEUE_DELETE, queueCB);
534 ret = LOS_MemFree(m_aucSysMem1, (VOID *)queue);//释放队列句柄
535 return ret;
536
537QUEUE_END:
538 SCHEDULER_UNLOCK(intSave);
539 return ret;
540}
541///外部接口, 获取队列信息,用queueInfo 把 LosQueueCB数据接走,QUEUE_INFO_S对内部数据的封装
542LITE_OS_SEC_TEXT_MINOR UINT32 LOS_QueueInfoGet(UINT32 queueID, QUEUE_INFO_S *queueInfo)
543{
544 UINT32 intSave;
545 UINT32 ret = LOS_OK;
546 LosQueueCB *queueCB = NULL;
547 LosTaskCB *tskCB = NULL;
548
549 if (queueInfo == NULL) {
550 return LOS_ERRNO_QUEUE_PTR_NULL;
551 }
552
553 if (GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {//1024
554 return LOS_ERRNO_QUEUE_INVALID;
555 }
556
557 (VOID)memset_s((VOID *)queueInfo, sizeof(QUEUE_INFO_S), 0, sizeof(QUEUE_INFO_S));//接走数据之前先清0
558 SCHEDULER_LOCK(intSave);
559
560 queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueID);//通过队列ID获取 QCB
561 if ((queueCB->queueID != queueID) || (queueCB->queueState == OS_QUEUE_UNUSED)) {
562 ret = LOS_ERRNO_QUEUE_NOT_CREATE;
563 goto QUEUE_END;
564 }
565
566 queueInfo->uwQueueID = queueID;
567 queueInfo->usQueueLen = queueCB->queueLen;
568 queueInfo->usQueueSize = queueCB->queueSize;
569 queueInfo->usQueueHead = queueCB->queueHead;
570 queueInfo->usQueueTail = queueCB->queueTail;
571 queueInfo->usReadableCnt = queueCB->readWriteableCnt[OS_QUEUE_READ];//可读数
572 queueInfo->usWritableCnt = queueCB->readWriteableCnt[OS_QUEUE_WRITE];//可写数
573
574 LOS_DL_LIST_FOR_EACH_ENTRY(tskCB, &queueCB->readWriteList[OS_QUEUE_READ], LosTaskCB, pendList) {//找出哪些task需要读消息
575 queueInfo->uwWaitReadTask |= 1ULL << tskCB->taskID;//记录等待读消息的任务号, uwWaitReadTask 每一位代表一个任务编号
576 }//0b..011011011 代表 0,1,3,4,6,7 号任务有数据等待读消息.
577
578 LOS_DL_LIST_FOR_EACH_ENTRY(tskCB, &queueCB->readWriteList[OS_QUEUE_WRITE], LosTaskCB, pendList) {//找出哪些task需要写消息
579 queueInfo->uwWaitWriteTask |= 1ULL << tskCB->taskID;//记录等待写消息的任务号, uwWaitWriteTask 每一位代表一个任务编号
580 }////0b..011011011 代表 0,1,3,4,6,7 号任务有数据等待写消息.
581
582 LOS_DL_LIST_FOR_EACH_ENTRY(tskCB, &queueCB->memList, LosTaskCB, pendList) {//同上
583 queueInfo->uwWaitMemTask |= 1ULL << tskCB->taskID; //MailBox模块使用
584 }
585
586QUEUE_END:
587 SCHEDULER_UNLOCK(intSave);
588 return ret;
589}
590
591#endif /* (LOSCFG_BASE_IPC_QUEUE == YES) */
592
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list)
Definition: los_list.h:104
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListTailInsert(LOS_DL_LIST *list, LOS_DL_LIST *node)
Insert a node to the tail of a doubly linked list.
Definition: los_list.h:244
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListDelete(LOS_DL_LIST *node)
Definition: los_list.h:292
LITE_OS_SEC_ALW_INLINE STATIC INLINE BOOL LOS_ListEmpty(LOS_DL_LIST *list)
Identify whether a specified doubly linked list is empty. | 判断链表是否为空
Definition: los_list.h:321
VOID * LOS_MemAlloc(VOID *pool, UINT32 size)
从指定内存池中申请size长度的内存,注意这可不是从内核堆空间中申请内存
Definition: los_memory.c:1123
UINT8 * m_aucSysMem1
系统动态内存池地址的起始地址 @note_thinking 能否不要用 0,1来命名核心变量 ???
Definition: los_memory.c:108
UINT32 LOS_MemFree(VOID *pool, VOID *ptr)
释放从指定动态内存中申请的内存
Definition: los_memory.c:1369
UINT8 * m_aucSysMem0
异常交互动态内存池地址的起始地址,当不支持异常交互特性时,m_aucSysMem0等于m_aucSysMem1。
Definition: los_memory.c:107
LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteHeadCopy(UINT32 queueID, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeout)
接口函数从队列头开始写
Definition: los_queue.c:394
LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteHead(UINT32 queueID, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeout)
Write data into a queue header.
Definition: los_queue.c:466
LITE_OS_SEC_BSS LosQueueCB * g_allQueue
消息队列池
Definition: los_queue.c:98
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_QueueInfoGet(UINT32 queueID, QUEUE_INFO_S *queueInfo)
外部接口, 获取队列信息,用queueInfo 把 LosQueueCB数据接走,QUEUE_INFO_S对内部数据的封装
Definition: los_queue.c:542
LITE_OS_SEC_TEXT UINT32 LOS_QueueReadCopy(UINT32 queueID, VOID *bufferAddr, UINT32 *bufferSize, UINT32 timeout)
接口函数定时读取消息队列
Definition: los_queue.c:377
LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueCreate(CHAR *queueName, UINT16 len, UINT32 *queueID, UINT32 flags, UINT16 maxMsgSize)
创建一个队列,根据用户传入队列长度和消息节点大小来开辟相应的内存空间以供该队列使用,参数queueID带走队列ID
Definition: los_queue.c:131
LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueDelete(UINT32 queueID)
Delete a queue.
Definition: los_queue.c:486
LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteCopy(UINT32 queueID, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeout)
接口函数 从队列尾部开始写
Definition: los_queue.c:411
LITE_OS_SEC_TEXT UINT32 LOS_QueueRead(UINT32 queueID, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeout)
Read a queue.
Definition: los_queue.c:436
LITE_OS_SEC_TEXT UINT32 LOS_QueueWrite(UINT32 queueID, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeout)
Write data into a queue.
Definition: los_queue.c:449
struct tagQueueInfo QUEUE_INFO_S
VOID LOS_Schedule(VOID)
Trigger active task scheduling.
Definition: los_sched.c:469
VOID LOS_MpSchedule(UINT32 target)
Definition: los_mp.c:76
STATIC LITE_OS_SEC_TEXT UINT32 OsQueueReadParameterCheck(UINT32 queueID, const VOID *bufferAddr, const UINT32 *bufferSize, UINT32 timeout)
读队列参数检查
Definition: los_queue.c:196
STATIC UINT32 OsQueueOperateParamCheck(const LosQueueCB *queueCB, UINT32 queueID, UINT32 operateType, const UINT32 *bufferSize)
队列操作参数检查
Definition: los_queue.c:298
UINT32 OsQueueOperate(UINT32 queueID, UINT32 operateType, VOID *bufferAddr, UINT32 *bufferSize, UINT32 timeout)
队列操作.是读是写由operateType定 本函数是消息队列最重要的一个函数,可以分析出读取消息过程中 发生的细节,涉及任务的唤醒和阻塞,阻塞链表任务的相互提醒.
Definition: los_queue.c:322
STATIC LITE_OS_SEC_TEXT UINT32 OsQueueWriteParameterCheck(UINT32 queueID, const VOID *bufferAddr, const UINT32 *bufferSize, UINT32 timeout)
写队列参数检查
Definition: los_queue.c:220
STATIC VOID OsQueueBufferOperate(LosQueueCB *queueCB, UINT32 operateType, VOID *bufferAddr, UINT32 *bufferSize)
队列buf操作,注意队列数据是按顺序来读取的,要不从头,要不从尾部,不会出现从中间读写,所有可由 head 和 tail 来管理队列.
Definition: los_queue.c:245
LITE_OS_SEC_TEXT_INIT UINT32 OsQueueInit(VOID)
Definition: los_queue.c:105
LITE_OS_SEC_BSS STATIC LOS_DL_LIST g_freeQueueList
空闲队列链表,管分配的,需要队列从这里申请
Definition: los_queue.c:99
STATIC INLINE VOID OsQueueDbgTimeUpdateHook(UINT32 queueID)
STATIC INLINE VOID OsQueueCheckHook(VOID)
STATIC INLINE VOID OsQueueDbgUpdateHook(UINT32 queueID, TSK_ENTRY_FUNC entry)
STATIC INLINE UINT32 OsQueueDbgInitHook(VOID)
@ OS_QUEUE_TAIL
队列尾部标识
Definition: los_queue_pri.h:70
@ OS_QUEUE_HEAD
队列头部标识
Definition: los_queue_pri.h:69
@ OS_QUEUE_WRITE
写队列
Definition: los_queue_pri.h:64
@ OS_QUEUE_READ
读队列
Definition: los_queue_pri.h:63
STATIC INLINE LosTaskCB * OsCurrTaskGet(VOID)
STATIC INLINE BOOL OsPreemptableInSched(VOID)
STATIC INLINE VOID OsTaskWaitSetPendMask(UINT16 mask, UINTPTR lockID, UINT32 timeout)
设置事件阻塞掩码,即设置任务的等待事件.
Definition: los_task_pri.h:289
STATIC INLINE VOID OsTaskWakeClearPendMask(LosTaskCB *resumeTask)
清除事件阻塞掩码,即任务不再等待任何事件.
Definition: los_task_pri.h:298
unsigned short UINT16
Definition: los_typedef.h:56
unsigned char UINT8
Definition: los_typedef.h:55
unsigned int UINT32
Definition: los_typedef.h:57
char CHAR
Definition: los_typedef.h:63
UINT16 queueHead
Definition: los_queue_pri.h:94
UINT16 readWriteableCnt[OS_QUEUE_N_RW]
Definition: los_queue_pri.h:96
UINT16 queueLen
Definition: los_queue_pri.h:91
UINT16 queueTail
Definition: los_queue_pri.h:95
LOS_DL_LIST memList
UINT16 queueSize
Definition: los_queue_pri.h:92
UINT16 queueState
Definition: los_queue_pri.h:90
UINT8 * queueHandle
Definition: los_queue_pri.h:89
UINT32 queueID
Definition: los_queue_pri.h:93
LOS_DL_LIST readWriteList[OS_QUEUE_N_RW]
Definition: los_queue_pri.h:98
UINT32(* wait)(LosTaskCB *runTask, LOS_DL_LIST *list, UINT32 timeout)
任务等待
VOID(* wake)(LosTaskCB *taskCB)
任务唤醒
UINT32 taskID
const SchedOps * ops
UINT64 uwWaitReadTask
Definition: los_queue.h:346
UINT16 usQueueTail
Definition: los_queue.h:343
UINT64 uwWaitMemTask
Definition: los_queue.h:348
UINT16 usWritableCnt
Definition: los_queue.h:344
UINT16 usQueueHead
Definition: los_queue.h:342
UINT16 usQueueSize
Definition: los_queue.h:341
UINT64 uwWaitWriteTask
Definition: los_queue.h:347
UINT32 uwQueueID
Definition: los_queue.h:339
UINT16 usQueueLen
Definition: los_queue.h:340
UINT16 usReadableCnt
Definition: los_queue.h:345