Messaging / IPC¶
Messaging API for inter process communication.
Messages¶
IPC messages consist of a sender PID, a type, and some content. The sender PID will be set by the IPC internally and is not required to be set by the user. The type helps the receiver to multiplex different message types and should be set to a system-wide unique value. The content can either be provided as a 32-bit integer or a pointer.
Blocking vs non-blocking¶
Messages can be sent and received blocking and non-blocking. Both can be used combined: A message send while blocking the sender thread can be received with the non-blocking variant and vice-versa.
Blocking IPC¶
For the blocking variant use msg.h::msg_send()
or msg.h::msg_receive()
respectively.
Additionally, one can use msg.h::msg_send_receive()
to simultaneously block the sending thread and expect a response from the receiving thread. In this case, the receiving thread must use msg.h::msg_reply()
to reply to the message of the sender thread.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include <inttypes.h>
#include <stdio.h>
#include "msg.h"
#include "thread.h"
static kernel_pid_t rcv_pid;
static char rcv_stack[THREAD_STACKSIZE_DEFAULT];
static void *rcv(void *arg)
{
msg_t msg_req, msg_resp;
(void)arg;
while (1) {
msg_receive(&msg_req);
msg_resp.content.value = msg_req.content.value + 1;
msg_reply(&msg_req, &msg_resp);
}
return NULL;
}
int main(void)
{
msg_t msg_req, msg_resp;
msg_resp.content.value = 0;
rcv_pid = thread_create(rcv_stack, sizeof(rcv_stack),
THREAD_PRIORITY_MAIN - 1, 0, rcv, NULL, "rcv");
while (1) {
msg_req.content.value = msg_resp.content.value;
msg_send_receive(&msg_req, &msg_resp, rcv_pid);
printf("Result: %" PRIu32 "\n", msg_resp.content.value);
}
return 0;
}
|
Non-blocking IPC¶
For the non-blocking variant use msg.h::msg_try_send()
or msg.h::msg_try_receive()
respectively. If a message is sent in synchronous mode or the message queue (see below) of the receiving thread is full messages sent this way will be dropped.
You can use the example on asynchronous IPC below - but without the queue - to get an impression of how to use non-blocking IPC.
Blocking IPC¶
For the blocking variant use msg.h::msg_send()
or msg.h::msg_receive()
respectively.
Additionally, one can use msg.h::msg_send_receive()
to simultaneously block the sending thread and expect a response from the receiving thread. In this case, the receiving thread must use msg.h::msg_reply()
to reply to the message of the sender thread.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include <inttypes.h>
#include <stdio.h>
#include "msg.h"
#include "thread.h"
static kernel_pid_t rcv_pid;
static char rcv_stack[THREAD_STACKSIZE_DEFAULT];
static void *rcv(void *arg)
{
msg_t msg_req, msg_resp;
(void)arg;
while (1) {
msg_receive(&msg_req);
msg_resp.content.value = msg_req.content.value + 1;
msg_reply(&msg_req, &msg_resp);
}
return NULL;
}
int main(void)
{
msg_t msg_req, msg_resp;
msg_resp.content.value = 0;
rcv_pid = thread_create(rcv_stack, sizeof(rcv_stack),
THREAD_PRIORITY_MAIN - 1, 0, rcv, NULL, "rcv");
while (1) {
msg_req.content.value = msg_resp.content.value;
msg_send_receive(&msg_req, &msg_resp, rcv_pid);
printf("Result: %" PRIu32 "\n", msg_resp.content.value);
}
return 0;
}
|
Non-blocking IPC¶
For the non-blocking variant use msg.h::msg_try_send()
or msg.h::msg_try_receive()
respectively. If a message is sent in synchronous mode or the message queue (see below) of the receiving thread is full messages sent this way will be dropped.
You can use the example on asynchronous IPC below - but without the queue - to get an impression of how to use non-blocking IPC.
Synchronous vs Asynchronous¶
RIOT’s IPC supports both synchronous and asynchronous IPC.
Synchronous IPC¶
Synchronous IPC is the default mode i.e. is active when the receiving thread has no message queue initialized. Messages that can’t be delivered when sending non-blocking (because the receiver already received a message) or which are sent when the receiver is not receive-blocked will be dropped.
Asynchronous IPC¶
To use asynchronous IPC one needs to initialize a message queue using msg.h::msg_init_queue()
(note that it must be of a size equal to a power of two). Messages sent to a thread with a message queue that isn’t full are never dropped and the sending never blocks, even when using msg.h::msg_send()
. If the queue is full and the sending thread has a higher priority than the receiving thread the send-behavior is equivalent to synchronous mode.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #include <inttypes.h>
#include <stdio.h>
#include "msg.h"
#include "thread.h"
#define RCV_QUEUE_SIZE (8)
static kernel_pid_t rcv_pid;
static char rcv_stack[THREAD_STACKSIZE_DEFAULT + THREAD_EXTRA_STACKSIZE_PRINTF];
static msg_t rcv_queue[RCV_QUEUE_SIZE];
static void *rcv(void *arg)
{
msg_t msg;
(void)arg;
msg_init_queue(rcv_queue, RCV_QUEUE_SIZE);
while (1) {
msg_receive(&msg);
printf("Received %" PRIu32 "\n", msg.content.value);
}
return NULL;
}
int main(void)
{
msg_t msg;
msg.content.value = 0;
rcv_pid = thread_create(rcv_stack, sizeof(rcv_stack),
THREAD_PRIORITY_MAIN - 1, 0, rcv, NULL, "rcv");
while (1) {
if (msg_try_send(&msg, rcv_pid) == 0) {
printf("Receiver queue full.\n");
}
msg.content.value++;
}
return 0;
}
|
Synchronous IPC¶
Synchronous IPC is the default mode i.e. is active when the receiving thread has no message queue initialized. Messages that can’t be delivered when sending non-blocking (because the receiver already received a message) or which are sent when the receiver is not receive-blocked will be dropped.
Asynchronous IPC¶
To use asynchronous IPC one needs to initialize a message queue using msg.h::msg_init_queue()
(note that it must be of a size equal to a power of two). Messages sent to a thread with a message queue that isn’t full are never dropped and the sending never blocks, even when using msg.h::msg_send()
. If the queue is full and the sending thread has a higher priority than the receiving thread the send-behavior is equivalent to synchronous mode.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #include <inttypes.h>
#include <stdio.h>
#include "msg.h"
#include "thread.h"
#define RCV_QUEUE_SIZE (8)
static kernel_pid_t rcv_pid;
static char rcv_stack[THREAD_STACKSIZE_DEFAULT + THREAD_EXTRA_STACKSIZE_PRINTF];
static msg_t rcv_queue[RCV_QUEUE_SIZE];
static void *rcv(void *arg)
{
msg_t msg;
(void)arg;
msg_init_queue(rcv_queue, RCV_QUEUE_SIZE);
while (1) {
msg_receive(&msg);
printf("Received %" PRIu32 "\n", msg.content.value);
}
return NULL;
}
int main(void)
{
msg_t msg;
msg.content.value = 0;
rcv_pid = thread_create(rcv_stack, sizeof(rcv_stack),
THREAD_PRIORITY_MAIN - 1, 0, rcv, NULL, "rcv");
while (1) {
if (msg_try_send(&msg, rcv_pid) == 0) {
printf("Receiver queue full.\n");
}
msg.content.value++;
}
return 0;
}
|
Timing & messages¶
Timing out the reception of a message or sending messages at a certain time is out of scope for the basic IPC provided by the kernel. See the xtimer module on information for these functionalities.
-
int
msg_send
(msg_t * m,kernel_types.h::kernel_pid_t
target_pid)¶ Send a message (blocking).
This function sends a message to another thread. The
msg_t
structure has to be allocated (e.g. on the stack) before calling the function and can be freed afterwards. If called from an interrupt, this function will never block.Parameters
m: Pointer to preallocated msg_t
structure, must not be NULL.target_pid: PID of target thread Return values
- 1, if sending was successful (message delivered directly or to a queue)
- 0, if called from ISR and receiver cannot receive the message now (it is not waiting or it’s message queue is full)
- -1, on error (invalid PID)
-
int
msg_try_send
(msg_t * m,kernel_types.h::kernel_pid_t
target_pid)¶ Send a message (non-blocking).
This function sends a message to another thread. The
msg_t
structure has to be allocated (e.g. on the stack) before calling the function and can be freed afterwards. This function will never block.Parameters
m: Pointer to preallocated msg_t
structure, must not be NULL.target_pid: PID of target thread Return values
- 1, if sending was successful (message delivered directly or to a queue)
- 0, if receiver is not waiting or has a full message queue
- -1, on error (invalid PID)
-
int
msg_send_to_self
(msg_t * m)¶ Send a message to the current thread.
Will work only if the thread has a message queue.
Will be automatically chosen instead of
msg_send
iftarget_pid
==thread_pid
. This function never blocks.Parameters
m: pointer to message structure Return values
- 1 if sending was successful
- 0 if the thread’s message queue is full (or inexistent)
-
int
msg_send_int
(msg_t * m,kernel_types.h::kernel_pid_t
target_pid)¶ Send message from interrupt.
Will be automatically chosen instead of
msg.h::msg_send()
if called from an interrupt/ISR.The value of
m->sender_pid
is set tomsg.h::KERNEL_PID_ISR
.See also
Parameters
m: Pointer to preallocated msg_t structure, must not be NULL. target_pid: PID of target thread. Return values
- 1, if sending was successful
- 0, if receiver is not waiting and
block == 0
- -1, on error (invalid PID)
-
int
msg_sent_by_int
(const msg_t * m)¶ Test if the message was sent inside an ISR.
See also
Parameters
m: The message in question. Return values
== 0
if not sent by an ISR!= 0
if sent by an ISR
-
int
msg_receive
(msg_t * m)¶ Receive a message.
This function blocks until a message was received.
Parameters
m: Pointer to preallocated msg_t
structure, must not be NULL.Return values
- 1, Function always succeeds or blocks forever.
-
int
msg_try_receive
(msg_t * m)¶ Try to receive a message.
This function does not block if no message can be received.
Parameters
m: Pointer to preallocated msg_t
structure, must not be NULL.Return values
- 1, if a message was received
- -1, otherwise.
-
int
msg_send_receive
(msg_t * m, msg_t * reply,kernel_types.h::kernel_pid_t
target_pid)¶ Send a message, block until reply received.
This function sends a message to target_pid and then blocks until target has sent a reply which is then stored in reply.
Parameters
m: Pointer to preallocated msg_t
structure with the message to send, must not be NULL.reply: Pointer to preallocated msg. Reply will be written here, must not be NULL. Can be identical to m
.target_pid: The PID of the target process Return values
- 1, if successful.
-
int
msg_reply
(msg_t * m, msg_t * reply)¶ Replies to a message.
Sender must have sent the message with
msg.h::msg_send_receive()
.Parameters
m: message to reply to, must not be NULL. reply: message that target will get as reply, must not be NULL. Return values
- 1, if successful
- -1, on error
-
int
msg_reply_int
(msg_t * m, msg_t * reply)¶ Replies to a message from interrupt.
An ISR can obviously not receive messages, however a thread might delegate replying to a message to an ISR.
Parameters
m: message to reply to, must not be NULL. reply: message that target will get as reply, must not be NULL. Return values
- 1, if successful
- -1, on error
-
int
msg_avail
(void)¶ Check how many messages are available in the message queue.
Return values
- Number of messages available in our queue on success
- -1, if no caller’s message queue is initialized
-
void
msg_init_queue
(msg_t * array, int num)¶ Initialize the current thread’s message queue.
Parameters
array: Pointer to preallocated array of msg_t
structures, must not be NULL.num: Number of msg_t
structures in array. MUST BE POWER OF TWO!
-
void
msg_queue_print
(void)¶ Prints the message queue of the current thread.
-
KERNEL_PID_ISR
¶ Value of
msg.h::msg_t::sender_pid
if the sender was an interrupt service routine.1
(KERNEL_PID_LAST + 1)
-
struct
msg_t
¶ Describes a message object which can be sent between threads.
User can set type and one of content.ptr and content.value. (content is a union) The meaning of type and the content fields is totally up to the user, the corresponding fields are never read by the kernel.
-
kernel_types.h::kernel_pid_t
sender_pid
¶ PID of sending thread.
Will be filled in by msg_send.
-
uint16_t
type
¶ Type field.
-
void *
ptr
¶ Pointer content field.
-
uint32_t
value
¶ Value content field.
-
union msg_t::@2
content
¶ Content of the message.
-