1# Queue 2 3 4## Basic Concepts 5 6A queue, also called a message queue, is a data structure used for communication between tasks. The queue receives messages of unfixed length from tasks or interrupts, and determines whether to store the transferred messages in the queue based on different APIs. 7 8Tasks can read messages from a queue. When the queue has no messages, the tasks are suspended. When the queue has a new message, the suspended tasks are woken up and process the new message. Tasks can also write messages to the queue. When the queue is full, the write task is suspended. When there is an available message node in the queue, the suspended write task is woken up and writes a message. 9 10You can adjust the timeout period of the read queue and write queue to adjust the block mode of the read and write APIs. If the timeout period is set to **0** for the read queue and write queue, tasks will not be suspended and the API directly returns. This is the non-block mode. If the timeout period is greater than **0**, block mode is used. 11 12An asynchronous processing mechanism is provided to allow messages in a queue not to be processed immediately. In addition, queues can be used to buffer messages and implement asynchronous task communication. Queues have the following features: 13 14- Messages are queued in first-in-first-out (FIFO) mode and can be read and written asynchronously. 15 16- Both the read queue and write queue support the timeout mechanism. 17 18- Each time a message is read, the message node becomes available. 19 20- The types of messages to be sent are determined by the parties involved in communication. Messages of different lengths (not exceeding the message node size of the queue) are allowed. 21 22- A task can receive messages from and send messages to any message queue. 23 24- Multiple tasks can receive messages from and send messages to the same queue. 25 26- When a queue is created, the required dynamic memory space is automatically allocated in the queue API. 27 28 29## Working Principles 30 31 32### Queue Control Block 33 34 35``` 36/** 37 * Data structure of the queue control block 38 */ 39typedef struct { 40 UINT8 *queueHandle; /**< Pointer to a queue handle */ 41 UINT16 queueState; /**< Queue state */ 42 UINT16 queueLen; /**< Queue length */ 43 UINT16 queueSize; /**< Node size */ 44 UINT32 queueID; /**< queueID */ 45 UINT16 queueHead; /**< Node head */ 46 UINT16 queueTail; /**< Node tail */ 47 UINT16 readWriteableCnt[OS_QUEUE_N_RW]; /**< Count of readable or writable resources, 0:readable, 1:writable */ 48 LOS_DL_LIST readWriteList[OS_QUEUE_N_RW]; /**< the linked list to be read or written, 0:readlist, 1:writelist */ 49 LOS_DL_LIST memList; /**< Pointer to the memory linked list */ 50} LosQueueCB; 51``` 52 53Each queue control block contains information about the queue status. 54 55- **OS_QUEUE_UNUSED**: The queue is not in use. 56 57- **OS_QUEUE_INUSED**: The queue is in use. 58 59 60### Working Principles 61 62- The queue ID is returned when a queue is created successfully. 63 64- The queue control block contains **Head** and **Tail**, which indicate the storage status of messages in a queue. **Head** indicates the start position of occupied message nodes in the queue. **Tail** indicates the end position of the occupied message nodes and the start position of idle message nodes. When a queue is created, **Head** and **Tail** point to the start position of the queue. 65 66- When data is to be written to a queue, **readWriteableCnt[1]** is used to determine whether data can be written to the queue. If **readWriteableCnt[1]** is **0**, the queue is full and data cannot be written to it. Data can be written to the head node or tail node of a queue. To write data to the tail node, locate the start idle message node based on **Tail** and write data to it. If **Tail** is pointing to the tail of the queue, the rewind mode is used. To write data to the head node, locate previous node based on **Head** and write data to it. If **Head** is pointing to the start position of the queue, the rewind mode is used. 67 68- When a queue is to be read, **readWriteableCnt[0]** is used to determine whether the queue has messages to read. Reading an idle queue (**readWriteableCnt[0]** is** 0**) will cause task suspension. If the queue has messages to read, the system locates the first node to which data is written based on **Head** and read the message from the node. If **Head** is pointing to the tail of the queue, the rewind mode is used. 69 70- When a queue is to be deleted, the system locates the queue based on the queue ID, sets the queue status to **OS_QUEUE_UNUSED**, sets the queue control block to the initial state, and releases the memory occupied by the queue. 71 72 **Figure 1** Reading and writing data in a queue 73 74 ![](figures/reading-and-writing-data-in-a-queue-3.png "reading-and-writing-data-in-a-queue-3") 75 76The preceding figure illustrates how to write data to the tail node only. Writing data to the head node is similar. 77 78 79## Development Guidelines 80 81 82### Available APIs 83 84| Category| API Description | 85| -------- | -------- | 86| Creating or deleting a message queue| - **LOS_QueueCreate**: creates a message queue. The system dynamically allocates the queue space.<br>- **LOS_QueueDelete**: deletes a queue.| 87| Reading or writing data (address without the content) in a queue| - **LOS_QueueRead**: reads data in the head node of the specified queue. The data in the queue node is an address.<br>- **LOS_QueueWrite**: writes the value of **bufferAddr** (buffer address) to the tail node of a queue.<br>- **LOS_QueueWrite**: writes the value of **bufferAddr** (buffer address) to the head node of a queue.| 88| Reading or writing data (data and address) in a queue| - **LOS_QueueReadCopy**: reads data from the head node of a queue.<br>- **LOS_QueueWriteCopy**: writes the data saved in **bufferAddr** to the tail node of a queue.<br>- **LOS_QueueWriteHeadCopy**: writes the data saved in **bufferAddr** to the head node of a queue.| 89| Obtaining queue information| **LOS_QueueInfoGet**: obtains queue information, including the queue ID, queue length, message node size, head node, tail node, number of readable/writable nodes, and tasks waiting for read/write operations.| 90 91 92### How to Develop 93 941. Call **LOS_QueueCreate** to create a queue. The queue ID is returned when the queue is created. 95 962. Call **LOS_QueueWrite** or **LOS_QueueWriteCopy** to write data to the queue. 97 983. Call **LOS_QueueRead** or **LOS_QueueReadCopy** to read data from the queue. 99 1004. Call **LOS_QueueInfoGet** to obtain queue information. 101 1025. Call **LOS_QueueDelete** to delete a queue. 103 104> **NOTE**<br> 105> - The maximum number of queues supported by the system is the total number of queue resources of the system, not the number of queue resources available to users. For example, if the system software timer occupies one more queue resource, the number of queue resources available to users decreases by one. 106> 107> - The queue name and flags passed in when a queue is created are reserved for future use. 108> 109> - The parameter **timeOut** in the queue function is relative time. 110> 111> - **LOS_QueueReadCopy**, **LOS_QueueWriteCopy**, and **LOS_QueueWriteHeadCopy** are a group of APIs that must be used together. **LOS_QueueRead**, **LOS_QueueWrite**, and **LOS_QueueWriteHead** are a group of APIs that must be used together. 112> 113> - As **LOS_QueueWrite**, **LOS_QueueWriteHead**, and **LOS_QueueRead** are used to manage data addresses, you must ensure that the memory directed by the pointer obtained by calling **LOS_QueueRead** is not modified or released abnormally when the queue is being read. Otherwise, unpredictable results may occur. 114> 115> - If the length of the data to read in **LOS_QueueRead** or **LOS_QueueReadCopy** is less than the actual message length, the message will be truncated. 116> 117> - **LOS_QueueWrite**, **LOS_QueueWriteHead**, and **LOS_QueueRead** are called to manage data addresses, which means that the actual data read or written is pointer data. Therefore, before using these APIs, ensure that the message node size is the pointer length during queue creation, to avoid waste and read failures. 118 119 120## Development Example 121 122 123### Example Description 124 125Create a queue and two tasks. Enable task 1 to write data to the queue, and task 2 to read data from the queue. 126 1271. Call **LOS_TaskCreate** to create task 1 and task 2. 128 1292. Call **LOS_QueueCreate** to create a message queue. 130 1313. Task 1 sends a message in **SendEntry**. 132 1334. Task 2 receives message in **RecvEntry**. 134 1355. Call **LOS_QueueDelete** to delete the queue. 136 137 138### Sample Code 139 140The sample code can be compiled and verified in **./kernel/liteos_a/testsuites/kernel/src/osTest.c**. The **ExampleQueue** function is called in **TestTaskEntry**. 141 142To avoid excessive printing, call **LOS_Msleep(5000)** to cause a short delay before calling **ExampleQueue**. 143 144The sample code is as follows: 145 146``` 147#include "los_task.h" 148#include "los_queue.h" 149static UINT32 g_queue; 150#define BUFFER_LEN 50 151 152VOID SendEntry(VOID) 153{ 154 UINT32 ret = 0; 155 CHAR abuf[] = "test message"; 156 UINT32 len = sizeof(abuf); 157 158 ret = LOS_QueueWriteCopy(g_queue, abuf, len, 0); 159 if(ret != LOS_OK) { 160 dprintf("send message failure, error: %x\n", ret); 161 } 162} 163 164VOID RecvEntry(VOID) 165{ 166 UINT32 ret = 0; 167 CHAR readBuf[BUFFER_LEN] = {0}; 168 UINT32 readLen = BUFFER_LEN; 169 170 LOS_Msleep(1000); 171 ret = LOS_QueueReadCopy(g_queue, readBuf, &readLen, 0); 172 if(ret != LOS_OK) { 173 dprintf("recv message failure, error: %x\n", ret); 174 } 175 176 dprintf("recv message: %s\n", readBuf); 177 178 ret = LOS_QueueDelete(g_queue); 179 if(ret != LOS_OK) { 180 dprintf("delete the queue failure, error: %x\n", ret); 181 } 182 183 dprintf("delete the queue success!\n"); 184} 185 186UINT32 ExampleQueue(VOID) 187{ 188 dprintf("start queue example\n"); 189 UINT32 ret = 0; 190 UINT32 task1, task2; 191 TSK_INIT_PARAM_S initParam = {0}; 192 193 ret = LOS_QueueCreate("queue", 5, &g_queue, 0, 50); 194 if(ret != LOS_OK) { 195 dprintf("create queue failure, error: %x\n", ret); 196 } 197 198 dprintf("create the queue success!\n"); 199 200 initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)SendEntry; 201 initParam.usTaskPrio = 9; 202 initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; 203 initParam.pcName = "SendQueue"; 204 205 LOS_TaskLock(); 206 ret = LOS_TaskCreate(&task1, &initParam); 207 if(ret != LOS_OK) { 208 dprintf("create task1 failed, error: %x\n", ret); 209 LOS_QueueDelete(g_queue); 210 return ret; 211 } 212 213 initParam.pcName = "RecvQueue"; 214 initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)RecvEntry; 215 ret = LOS_TaskCreate(&task2, &initParam); 216 if(ret != LOS_OK) { 217 dprintf("create task2 failed, error: %x\n", ret); 218 LOS_QueueDelete(g_queue); 219 return ret; 220 } 221 222 LOS_TaskUnlock(); 223 LOS_Msleep(5000); 224 return ret; 225} 226``` 227 228 229### Verification 230 231The development is successful if the return result is as follows: 232 233 234``` 235start queue example 236create the queue success! 237recv message: test message 238delete the queue success! 239``` 240