1.. _message_queues_v2: 2 3Message Queues 4############## 5 6A :dfn:`message queue` is a kernel object that implements a simple 7message queue, allowing threads and ISRs to asynchronously send and receive 8fixed-size data items. 9 10.. contents:: 11 :local: 12 :depth: 2 13 14Concepts 15******** 16 17Any number of message queues can be defined (limited only by available RAM). 18Each message queue is referenced by its memory address. 19 20A message queue has the following key properties: 21 22* A **ring buffer** of data items that have been sent but not yet received. 23 24* A **data item size**, measured in bytes. 25 26* A **maximum quantity** of data items that can be queued in the ring buffer. 27 28A message queue must be initialized before it can be used. 29This sets its ring buffer to empty. 30 31A data item can be **sent** to a message queue by a thread or an ISR. 32The data item pointed at by the sending thread is copied to a waiting thread, 33if one exists; otherwise the item is copied to the message queue's ring buffer, 34if space is available. In either case, the size of the data area being sent 35*must* equal the message queue's data item size. 36 37If a thread attempts to send a data item when the ring buffer is full, 38the sending thread may choose to wait for space to become available. 39Any number of sending threads may wait simultaneously when the ring buffer 40is full; when space becomes available 41it is given to the highest priority sending thread that has waited the longest. 42 43A data item can be **received** from a message queue by a thread. 44The data item is copied to the area specified by the receiving thread; 45the size of the receiving area *must* equal the message queue's data item size. 46 47If a thread attempts to receive a data item when the ring buffer is empty, 48the receiving thread may choose to wait for a data item to be sent. 49Any number of receiving threads may wait simultaneously when the ring buffer 50is empty; when a data item becomes available it is given to 51the highest priority receiving thread that has waited the longest. 52 53A thread can also **peek** at the message on the head of a message queue without 54removing it from the queue. 55The data item is copied to the area specified by the receiving thread; 56the size of the receiving area *must* equal the message queue's data item size. 57 58.. note:: 59 The kernel does allow an ISR to receive an item from a message queue, 60 however the ISR must not attempt to wait if the message queue is empty. 61 62.. note:: 63 Alignment of the message queue's ring buffer is not necessary. 64 The underlying implementation uses :c:func:`memcpy` (which is 65 alignment-agnostic) and does not expose any internal pointers. 66 67Implementation 68************** 69 70Defining a Message Queue 71======================== 72 73A message queue is defined using a variable of type :c:struct:`k_msgq`. 74It must then be initialized by calling :c:func:`k_msgq_init`. 75 76The following code defines and initializes an empty message queue 77that is capable of holding 10 items, each of which is 12 bytes long. 78 79.. code-block:: c 80 81 struct data_item_type { 82 uint32_t field1; 83 uint32_t field2; 84 uint32_t field3; 85 }; 86 87 char my_msgq_buffer[10 * sizeof(struct data_item_type)]; 88 struct k_msgq my_msgq; 89 90 k_msgq_init(&my_msgq, my_msgq_buffer, sizeof(struct data_item_type), 10); 91 92Alternatively, a message queue can be defined and initialized at compile time 93by calling :c:macro:`K_MSGQ_DEFINE`. 94 95The following code has the same effect as the code segment above. Observe 96that the macro defines both the message queue and its buffer. 97 98.. code-block:: c 99 100 K_MSGQ_DEFINE(my_msgq, sizeof(struct data_item_type), 10, 1); 101 102Writing to a Message Queue 103========================== 104 105A data item is added to a message queue by calling :c:func:`k_msgq_put`. 106 107The following code builds on the example above, and uses the message queue 108to pass data items from a producing thread to one or more consuming threads. 109If the message queue fills up because the consumers can't keep up, the 110producing thread throws away all existing data so the newer data can be saved. 111Note that this api will trigger reschedule. 112 113.. code-block:: c 114 115 void producer_thread(void) 116 { 117 struct data_item_type data; 118 119 while (1) { 120 /* create data item to send (e.g. measurement, timestamp, ...) */ 121 data = ... 122 123 /* send data to consumers */ 124 while (k_msgq_put(&my_msgq, &data, K_NO_WAIT) != 0) { 125 /* message queue is full: purge old data & try again */ 126 k_msgq_purge(&my_msgq); 127 } 128 129 /* data item was successfully added to message queue */ 130 } 131 } 132 133Reading from a Message Queue 134============================ 135 136A data item is taken from a message queue by calling :c:func:`k_msgq_get`. 137 138The following code builds on the example above, and uses the message queue 139to process data items generated by one or more producing threads. Note that 140the return value of :c:func:`k_msgq_get` should be tested as ``-ENOMSG`` 141can be returned due to :c:func:`k_msgq_purge`. 142 143.. code-block:: c 144 145 void consumer_thread(void) 146 { 147 struct data_item_type data; 148 149 while (1) { 150 /* get a data item */ 151 k_msgq_get(&my_msgq, &data, K_FOREVER); 152 153 /* process data item */ 154 ... 155 } 156 } 157 158 159Peeking into a Message Queue 160============================ 161 162A data item is read from a message queue by calling :c:func:`k_msgq_peek`. 163 164The following code peeks into the message queue to read the data item at the 165head of the queue that is generated by one or more producing threads. 166 167.. code-block:: c 168 169 void consumer_thread(void) 170 { 171 struct data_item_type data; 172 173 while (1) { 174 /* read a data item by peeking into the queue */ 175 k_msgq_peek(&my_msgq, &data); 176 177 /* process data item */ 178 ... 179 } 180 } 181 182Suggested Uses 183************** 184 185Use a message queue to transfer small data items between threads 186in an asynchronous manner. 187 188.. note:: 189 A message queue can be used to transfer large data items, if desired. 190 However, this can increase interrupt latency as interrupts are locked 191 while a data item is written or read. The time to write or read a data item 192 increases linearly with its size since the item is copied in its entirety 193 to or from the buffer in memory. For this reason, it is usually preferable 194 to transfer large data items by exchanging a pointer to the data item, 195 rather than the data item itself. 196 197 A synchronous transfer can be achieved by using the kernel's mailbox 198 object type. 199 200Configuration Options 201********************* 202 203Related configuration options: 204 205* None. 206 207API Reference 208************* 209 210.. doxygengroup:: msgq_apis 211