1.. _mailboxes_v2:
2
3Mailboxes
4#########
5
6A :dfn:`mailbox` is a kernel object that provides enhanced message queue
7capabilities that go beyond the capabilities of a message queue object.
8A mailbox allows threads to send and receive messages of any size
9synchronously or asynchronously.
10
11.. contents::
12    :local:
13    :depth: 2
14
15Concepts
16********
17
18Any number of mailboxes can be defined (limited only by available RAM). Each
19mailbox is referenced by its memory address.
20
21A mailbox has the following key properties:
22
23* A **send queue** of messages that have been sent but not yet received.
24
25* A **receive queue** of threads that are waiting to receive a message.
26
27A mailbox must be initialized before it can be used. This sets both of its
28queues to empty.
29
30A mailbox allows threads, but not ISRs, to exchange messages.
31A thread that sends a message is known as the **sending thread**,
32while a thread that receives the message is known as the **receiving thread**.
33Each message may be received by only one thread (i.e. point-to-multipoint and
34broadcast messaging is not supported).
35
36Messages exchanged using a mailbox are handled non-anonymously,
37allowing both threads participating in an exchange to know
38(and even specify) the identity of the other thread.
39
40Message Format
41==============
42
43A **message descriptor** is a data structure that specifies where a message's
44data is located, and how the message is to be handled by the mailbox.
45Both the sending thread and the receiving thread supply a message descriptor
46when accessing a mailbox. The mailbox uses the message descriptors to perform
47a message exchange between compatible sending and receiving threads.
48The mailbox also updates certain message descriptor fields during the exchange,
49allowing both threads to know what has occurred.
50
51A mailbox message contains zero or more bytes of **message data**.
52The size and format of the message data is application-defined, and can vary
53from one message to the next.
54
55A **message buffer** is an area of memory provided by the thread that sends or
56receives the message data. An array or structure variable can often be used for
57this purpose.
58
59A message that has neither form of message data is called an **empty message**.
60
61.. note::
62    A message whose message buffer exists, but contains zero bytes of actual
63    data, is *not* an empty message.
64
65Message Lifecycle
66=================
67
68The life cycle of a message is straightforward. A message is created when
69it is given to a mailbox by the sending thread. The message is then owned
70by the mailbox until it is given to a receiving thread. The receiving thread
71may retrieve the message data when it receives the message from the mailbox,
72or it may perform data retrieval during a second, subsequent mailbox operation.
73Only when data retrieval has occurred is the message deleted by the mailbox.
74
75Thread Compatibility
76====================
77
78A sending thread can specify the address of the thread to which the message
79is sent, or send it to any thread by specifying :c:macro:`K_ANY`.
80Likewise, a receiving thread can specify the address of the thread from which
81it wishes to receive a message, or it can receive a message from any thread
82by specifying :c:macro:`K_ANY`.
83A message is exchanged only when the requirements of both the sending thread
84and receiving thread are satisfied; such threads are said to be **compatible**.
85
86For example, if thread A sends a message to thread B (and only thread B)
87it will be received by thread B if thread B tries to receive a message
88from thread A or if thread B tries to receive from any thread.
89The exchange will not occur if thread B tries to receive a message
90from thread C. The message can never be received by thread C,
91even if it tries to receive a message from thread A (or from any thread).
92
93Message Flow Control
94====================
95
96Mailbox messages can be exchanged **synchronously** or **asynchronously**.
97In a synchronous exchange, the sending thread blocks until the message
98has been fully processed by the receiving thread. In an asynchronous exchange,
99the sending thread does not wait until the message has been received
100by another thread before continuing; this allows the sending thread to do
101other work (such as gather data that will be used in the next message)
102*before* the message is given to a receiving thread and fully processed.
103The technique used for a given message exchange is determined
104by the sending thread.
105
106The synchronous exchange technique provides an implicit form of flow control,
107preventing a sending thread from generating messages faster than they can be
108consumed by receiving threads. The asynchronous exchange technique provides an
109explicit form of flow control, which allows a sending thread to determine
110if a previously sent message still exists before sending a subsequent message.
111
112Implementation
113**************
114
115Defining a Mailbox
116==================
117
118A mailbox is defined using a variable of type :c:struct:`k_mbox`.
119It must then be initialized by calling :c:func:`k_mbox_init`.
120
121The following code defines and initializes an empty mailbox.
122
123.. code-block:: c
124
125    struct k_mbox my_mailbox;
126
127    k_mbox_init(&my_mailbox);
128
129Alternatively, a mailbox can be defined and initialized at compile time
130by calling :c:macro:`K_MBOX_DEFINE`.
131
132The following code has the same effect as the code segment above.
133
134.. code-block:: c
135
136    K_MBOX_DEFINE(my_mailbox);
137
138Message Descriptors
139===================
140
141A message descriptor is a structure of type :c:struct:`k_mbox_msg`.
142Only the fields listed below should be used; any other fields are for
143internal mailbox use only.
144
145*info*
146    A 32-bit value that is exchanged by the message sender and receiver,
147    and whose meaning is defined by the application. This exchange is
148    bi-directional, allowing the sender to pass a value to the receiver
149    during any message exchange, and allowing the receiver to pass a value
150    to the sender during a synchronous message exchange.
151
152*size*
153    The message data size, in bytes. Set it to zero when sending an empty
154    message, or when sending a message buffer with no actual data. When
155    receiving a message, set it to the maximum amount of data desired, or to
156    zero if the message data is not wanted. The mailbox updates this field with
157    the actual number of data bytes exchanged once the message is received.
158
159*tx_data*
160    A pointer to the sending thread's message buffer. Set it to ``NULL``
161    when sending an empty message. Leave this field uninitialized when
162    receiving a message.
163
164*tx_target_thread*
165    The address of the desired receiving thread. Set it to :c:macro:`K_ANY`
166    to allow any thread to receive the message. Leave this field uninitialized
167    when receiving a message. The mailbox updates this field with
168    the actual receiver's address once the message is received.
169
170*rx_source_thread*
171    The address of the desired sending thread. Set it to :c:macro:`K_ANY`
172    to receive a message sent by any thread. Leave this field uninitialized
173    when sending a message. The mailbox updates this field
174    with the actual sender's address when the message is put into
175    the mailbox.
176
177Sending a Message
178=================
179
180A thread sends a message by first creating its message data, if any.
181
182Next, the sending thread creates a message descriptor that characterizes
183the message to be sent, as described in the previous section.
184
185Finally, the sending thread calls a mailbox send API to initiate the
186message exchange. The message is immediately given to a compatible receiving
187thread, if one is currently waiting. Otherwise, the message is added
188to the mailbox's send queue.
189
190Any number of messages may exist simultaneously on a send queue.
191The messages in the send queue are sorted according to the priority
192of the sending thread. Messages of equal priority are sorted so that
193the oldest message can be received first.
194
195For a synchronous send operation, the operation normally completes when a
196receiving thread has both received the message and retrieved the message data.
197If the message is not received before the waiting period specified by the
198sending thread is reached, the message is removed from the mailbox's send queue
199and the send operation fails. When a send operation completes successfully
200the sending thread can examine the message descriptor to determine
201which thread received the message, how much data was exchanged,
202and the application-defined info value supplied by the receiving thread.
203
204.. note::
205   A synchronous send operation may block the sending thread indefinitely,
206   even when the thread specifies a maximum waiting period.
207   The waiting period only limits how long the mailbox waits
208   before the message is received by another thread. Once a message is received
209   there is *no* limit to the time the receiving thread may take to retrieve
210   the message data and unblock the sending thread.
211
212For an asynchronous send operation, the operation always completes immediately.
213This allows the sending thread to continue processing regardless of whether the
214message is given to a receiving thread immediately or added to the send queue.
215The sending thread may optionally specify a semaphore that the mailbox gives
216when the message is deleted by the mailbox, for example, when the message
217has been received and its data retrieved by a receiving thread.
218The use of a semaphore allows the sending thread to easily implement
219a flow control mechanism that ensures that the mailbox holds no more than
220an application-specified number of messages from a sending thread
221(or set of sending threads) at any point in time.
222
223.. note::
224   A thread that sends a message asynchronously has no way to determine
225   which thread received the message, how much data was exchanged, or the
226   application-defined info value supplied by the receiving thread.
227
228Sending an Empty Message
229------------------------
230
231This code uses a mailbox to synchronously pass 4 byte random values
232to any consuming thread that wants one. The message "info" field is
233large enough to carry the information being exchanged, so the data
234portion of the message isn't used.
235
236.. code-block:: c
237
238    void producer_thread(void)
239    {
240        struct k_mbox_msg send_msg;
241
242        while (1) {
243
244            /* generate random value to send */
245            uint32_t random_value = sys_rand32_get();
246
247            /* prepare to send empty message */
248            send_msg.info = random_value;
249            send_msg.size = 0;
250            send_msg.tx_data = NULL;
251            send_msg.tx_target_thread = K_ANY;
252
253            /* send message and wait until a consumer receives it */
254            k_mbox_put(&my_mailbox, &send_msg, K_FOREVER);
255        }
256    }
257
258Sending Data Using a Message Buffer
259-----------------------------------
260
261This code uses a mailbox to synchronously pass variable-sized requests
262from a producing thread to any consuming thread that wants it.
263The message "info" field is used to exchange information about
264the maximum size message buffer that each thread can handle.
265
266.. code-block:: c
267
268    void producer_thread(void)
269    {
270        char buffer[100];
271        int buffer_bytes_used;
272
273        struct k_mbox_msg send_msg;
274
275        while (1) {
276
277            /* generate data to send */
278            ...
279            buffer_bytes_used = ... ;
280            memcpy(buffer, source, buffer_bytes_used);
281
282            /* prepare to send message */
283            send_msg.info = buffer_bytes_used;
284            send_msg.size = buffer_bytes_used;
285            send_msg.tx_data = buffer;
286            send_msg.tx_target_thread = K_ANY;
287
288            /* send message and wait until a consumer receives it */
289            k_mbox_put(&my_mailbox, &send_msg, K_FOREVER);
290
291            /* info, size, and tx_target_thread fields have been updated */
292
293            /* verify that message data was fully received */
294            if (send_msg.size < buffer_bytes_used) {
295                printf("some message data dropped during transfer!");
296                printf("receiver only had room for %d bytes", send_msg.info);
297            }
298        }
299    }
300
301Receiving a Message
302===================
303
304A thread receives a message by first creating a message descriptor that
305characterizes the message it wants to receive. It then calls one of the
306mailbox receive APIs. The mailbox searches its send queue and takes the message
307from the first compatible thread it finds. If no compatible thread exists,
308the receiving thread may choose to wait for one. If no compatible thread
309appears before the waiting period specified by the receiving thread is reached,
310the receive operation fails.
311Once a receive operation completes successfully the receiving thread
312can examine the message descriptor to determine which thread sent the message,
313how much data was exchanged,
314and the application-defined info value supplied by the sending thread.
315
316Any number of receiving threads may wait simultaneously on a mailboxes'
317receive queue. The threads are sorted according to their priority;
318threads of equal priority are sorted so that the one that started waiting
319first can receive a message first.
320
321.. note::
322    Receiving threads do not always receive messages in a first in, first out
323    (FIFO) order, due to the thread compatibility constraints specified by the
324    message descriptors. For example, if thread A waits to receive a message
325    only from thread X and then thread B waits to receive a message from
326    thread Y, an incoming message from thread Y to any thread will be given
327    to thread B and thread A will continue to wait.
328
329The receiving thread controls both the quantity of data it retrieves from an
330incoming message and where the data ends up. The thread may choose to take
331all of the data in the message, to take only the initial part of the data,
332or to take no data at all. Similarly, the thread may choose to have the data
333copied into a message buffer of its choice.
334
335The following sections outline various approaches a receiving thread may use
336when retrieving message data.
337
338Retrieving Data at Receive Time
339-------------------------------
340
341The most straightforward way for a thread to retrieve message data is to
342specify a message buffer when the message is received. The thread indicates
343both the location of the message buffer (which must not be ``NULL``)
344and its size.
345
346The mailbox copies the message's data to the message buffer as part of the
347receive operation. If the message buffer is not big enough to contain all of the
348message's data, any uncopied data is lost. If the message is not big enough
349to fill all of the buffer with data, the unused portion of the message buffer is
350left unchanged. In all cases the mailbox updates the receiving thread's
351message descriptor to indicate how many data bytes were copied (if any).
352
353The immediate data retrieval technique is best suited for small messages
354where the maximum size of a message is known in advance.
355
356The following code uses a mailbox to process variable-sized requests from any
357producing thread, using the immediate data retrieval technique. The message
358"info" field is used to exchange information about the maximum size
359message buffer that each thread can handle.
360
361.. code-block:: c
362
363    void consumer_thread(void)
364    {
365        struct k_mbox_msg recv_msg;
366        char buffer[100];
367
368        int i;
369        int total;
370
371        while (1) {
372            /* prepare to receive message */
373            recv_msg.info = 100;
374            recv_msg.size = 100;
375            recv_msg.rx_source_thread = K_ANY;
376
377            /* get a data item, waiting as long as needed */
378            k_mbox_get(&my_mailbox, &recv_msg, buffer, K_FOREVER);
379
380            /* info, size, and rx_source_thread fields have been updated */
381
382            /* verify that message data was fully received */
383            if (recv_msg.info != recv_msg.size) {
384                printf("some message data dropped during transfer!");
385                printf("sender tried to send %d bytes", recv_msg.info);
386            }
387
388            /* compute sum of all message bytes (from 0 to 100 of them) */
389            total = 0;
390            for (i = 0; i < recv_msg.size; i++) {
391                total += buffer[i];
392            }
393        }
394    }
395
396Retrieving Data Later Using a Message Buffer
397--------------------------------------------
398
399A receiving thread may choose to defer message data retrieval at the time
400the message is received, so that it can retrieve the data into a message buffer
401at a later time.
402The thread does this by specifying a message buffer location of ``NULL``
403and a size indicating the maximum amount of data it is willing to retrieve
404later.
405
406The mailbox does not copy any message data as part of the receive operation.
407However, the mailbox still updates the receiving thread's message descriptor
408to indicate how many data bytes are available for retrieval.
409
410The receiving thread must then respond as follows:
411
412* If the message descriptor size is zero, then either the sender's message
413  contained no data or the receiving thread did not want to receive any data.
414  The receiving thread does not need to take any further action, since
415  the mailbox has already completed data retrieval and deleted the message.
416
417* If the message descriptor size is non-zero and the receiving thread still
418  wants to retrieve the data, the thread must call :c:func:`k_mbox_data_get`
419  and supply a message buffer large enough to hold the data. The mailbox copies
420  the data into the message buffer and deletes the message.
421
422* If the message descriptor size is non-zero and the receiving thread does *not*
423  want to retrieve the data, the thread must call :c:func:`k_mbox_data_get`.
424  and specify a message buffer of ``NULL``. The mailbox deletes
425  the message without copying the data.
426
427The subsequent data retrieval technique is suitable for applications where
428immediate retrieval of message data is undesirable. For example, it can be
429used when memory limitations make it impractical for the receiving thread to
430always supply a message buffer capable of holding the largest possible
431incoming message.
432
433The following code uses a mailbox's deferred data retrieval mechanism
434to get message data from a producing thread only if the message meets
435certain criteria, thereby eliminating unneeded data copying. The message
436"info" field supplied by the sender is used to classify the message.
437
438.. code-block:: c
439
440    void consumer_thread(void)
441    {
442        struct k_mbox_msg recv_msg;
443        char buffer[10000];
444
445        while (1) {
446            /* prepare to receive message */
447            recv_msg.size = 10000;
448            recv_msg.rx_source_thread = K_ANY;
449
450            /* get message, but not its data */
451            k_mbox_get(&my_mailbox, &recv_msg, NULL, K_FOREVER);
452
453            /* get message data for only certain types of messages */
454            if (is_message_type_ok(recv_msg.info)) {
455                /* retrieve message data and delete the message */
456                k_mbox_data_get(&recv_msg, buffer);
457
458                /* process data in "buffer" */
459                ...
460            } else {
461                /* ignore message data and delete the message */
462                k_mbox_data_get(&recv_msg, NULL);
463            }
464        }
465    }
466
467Suggested Uses
468**************
469
470Use a mailbox to transfer data items between threads whenever the capabilities
471of a message queue are insufficient.
472
473Configuration Options
474*********************
475
476Related configuration options:
477
478* :kconfig:option:`CONFIG_NUM_MBOX_ASYNC_MSGS`
479
480API Reference
481*************
482
483.. doxygengroup:: mailbox_apis
484