1# Queue 2 3 4## Basic Concepts 5 6A message queue, also called a queue, is a mechanism for communication between tasks. The queue receives messages of unfixed length from tasks or interrupts, and determines whether to put the messages in the queue based on different APIs. 7 8Tasks can read messages from a queue. When the queue has no messages, the read task is suspended. When the queue has a new message, the suspended task is woken up to process new messages. 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- Both the read queue and write queue support the timeout mechanism. 16- Each time a message is read, the message node becomes available. 17- 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. 18- A task can receive messages from and send messages to any message queue. 19- Multiple tasks can receive messages from and send messages to the same queue. 20- The system dynamically applies for memory space required for creating normal queues. 21- The space required for creating a static queue is passed in by the user. When the static queue is deleted, the space also needs to be released by the user. 22 23 24## Working Principles 25 26### Queue Control Block 27 28During the initialization of a queue, a control block, containing the queue name and status, is allocated. The control block is released when the queue is deleted. 29 30The data structure of the queue control block is as follows: 31 32 33``` 34typedef struct 35{ 36 UINT8 *queue; /* Pointer to the memory space of the queue */ 37 UINT8 *queueName /* Queue name */ 38 UINT16 queueState; /* Queue status */ 39 UINT16 queueLen; /* Number of message nodes in the queue, that is, the queue length */ 40 UINT16 queueSize; /* Size of a message node */ 41 UINT16 queueID; /* Queue ID */ 42 UINT16 queueHead; /* Position of the message head node (array subscript) */ 43 UINT16 queueTail; /* Position of the message tail node (array subscript) */ 44 UINT16 readWriteableCnt[OS_READWRITE_LEN]; /* The element whose array subscript is 0 indicates the number of readable messages in the queue, 45 The element whose array subscript is 1 indicates the number of writable messages in the queue */ 46 LOS_DL_LIST readWriteList[OS_READWRITE_LEN]; /* A linked list of tasks waiting to read or write messages. 47 Subscript 0: read the linked list. Subscript 1: write the linked list. */ 48 LOS_DL_LIST memList; /* A linked list of memory blocks */ 49} LosQueueCB; 50``` 51 52Each queue control block contains information about the queue status. 53 54- **OS_QUEUE_UNUSED**: The queue is not in use. 55 56- **OS_QUEUE_INUSED**: The queue is in use. 57 58 59### Working Principles 60 61- The queue ID is returned when a queue is created successfully. 62 63- 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. 64 65- 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. 66 67- 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. 68 69- 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. 70 71 **Figure 1** Reading and writing data in a queue 72 73 ![](figures/reading-and-writing-data-in-a-queue.png "reading-and-writing-data-in-a-queue") 74 75The preceding figure illustrates how to write data to the tail node only. Writing data to the head node is similar. 76 77 78## Available APIs 79 80| Category| API Description | 81| -------- | -------- | 82| Creating or deleting a message queue| **LOS_QueueCreate**: creates a message queue. The system dynamically allocates the queue space.<br>**LOS_QueueCreateStatic**: creates a static message queue. You need to pass in the queue space.<br>**LOS_QueueDelete**: deletes a message queue. After a static message queue is deleted, you need to release the queue space.| 83| 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 **bufferAddr** (buffer address) to the tail node of the specified queue.<br>**LOS_QueueWriteHead**: writes the **bufferAddr** (buffer address) to the head node of the specified queue.| 84| Reading or writing data (data and address) in a queue| **LOS_QueueReadCopy**: reads data from the head node of a specified queue.<br>**LOS_QueueWriteCopy**: writes the data saved in the **bufferAddr** to the tail node of the specified queue.<br>**LOS_QueueWriteHeadCopy**: writes the data saved in the **bufferAddr** to the head node of the specified queue.| 85| 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.| 86 87 88## How to Develop 89 901. Call **LOS_QueueCreate** to create a queue. The queue ID is returned when the queue is created. 91 922. Call **LOS_QueueWrite** or **LOS_QueueWriteCopy** to write data to the queue. 93 943. Call **LOS_QueueRead** or **LOS_QueueReadCopy** to read data from the queue. 95 964. Call **LOS_QueueInfoGet** to obtain queue information. 97 985. Call **LOS_QueueDelete** to delete a queue. 99 100 101> **NOTE** 102> - 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. 103> 104> - The input parameters queue name and flags passed when a queue is created are reserved for future use. 105> 106> - The input parameter **timeOut** in the queue interface function is relative time. 107> 108> - **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. 109> 110> - 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. 111> 112> - If the read length of **LOS_QueueReadCopy** is less than the actual message length, the message will be truncated. 113> 114> - **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. 115 116 117## Development Example 118 119 120### Example Description 121 122Create a queue and two tasks. Enable task 1 to write data to the queue, and task 2 to read data from the queue. 123 1241. Call **LOS_TaskCreate** to create task 1 and task 2. 125 1262. Call **LOS_QueueCreate** to create a message queue. 127 1283. Task 1 sends a message in **SendEntry**. 129 1304. Task 2 receives message in **RecvEntry**. 131 1325. Call **LOS_QueueDelete** to delete the queue. 133 134 135### Sample Code 136 137The sample code is as follows: 138 139The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **ExampleQueue** function is called in **TestTaskEntry**. 140 141 142``` 143#include "los_task.h" 144#include "los_queue.h" 145 146STATIC UINT32 g_queue; 147#define BUFFER_LEN 50 148 149VOID SendEntry(VOID) 150{ 151 UINT32 ret = 0; 152 CHAR abuf[] = "test message"; 153 UINT32 len = sizeof(abuf); 154 155 ret = LOS_QueueWriteCopy(g_queue, abuf, len, 0); 156 if (ret != LOS_OK) { 157 printf("send message failure, error: %x\n", ret); 158 } 159} 160 161VOID RecvEntry(VOID) 162{ 163 UINT32 ret = 0; 164 CHAR readBuf[BUFFER_LEN] = {0}; 165 UINT32 readLen = BUFFER_LEN; 166 167 /* Sleep for 1s */ 168 usleep(1000000); 169 ret = LOS_QueueReadCopy(g_queue, readBuf, &readLen, 0); 170 if (ret != LOS_OK) { 171 printf("recv message failure, error: %x\n", ret); 172 } 173 174 printf("recv message: %s.\n", readBuf); 175 176 ret = LOS_QueueDelete(g_queue); 177 if (ret != LOS_OK) { 178 printf("delete the queue failure, error: %x\n", ret); 179 } 180 181 printf("delete the queue success.\n"); 182} 183 184UINT32 ExampleQueue(VOID) 185{ 186 printf("start queue example.\n"); 187 UINT32 ret = 0; 188 UINT32 task1; 189 UINT32 task2; 190 TSK_INIT_PARAM_S taskParam1 = { 0 }; 191 TSK_INIT_PARAM_S taskParam2 = { 0 }; 192 193 LOS_TaskLock(); 194 195 taskParam1.pfnTaskEntry = (TSK_ENTRY_FUNC)SendEntry; 196 taskParam1.usTaskPrio = 9; 197 taskParam1.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; 198 taskParam1.pcName = "SendQueue"; 199 ret = LOS_TaskCreate(&task1, &taskParam1); 200 if(ret != LOS_OK) { 201 printf("create task1 failed, error: %x\n", ret); 202 return ret; 203 } 204 205 taskParam2.pfnTaskEntry = (TSK_ENTRY_FUNC)RecvEntry; 206 taskParam2.usTaskPrio = 10; 207 taskParam2.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; 208 taskParam2.pcName = "RecvQueue"; 209 ret = LOS_TaskCreate(&task2, &taskParam2); 210 if(ret != LOS_OK) { 211 printf("create task2 failed, error: %x\n", ret); 212 return ret; 213 } 214 215 ret = LOS_QueueCreate("queue", 5, &g_queue, 0, 50); 216 if(ret != LOS_OK) { 217 printf("create queue failure, error: %x\n", ret); 218 } 219 220 printf("create the queue success.\n"); 221 LOS_TaskUnlock(); 222 return ret; 223} 224``` 225 226 227### Verification 228 229The development is successful if the return result is as follows: 230 231 232 233``` 234start queue example. 235create the queue success. 236recv message: test message. 237delete the queue success. 238``` 239