Loading...
Searching...
No Matches
Messaging / IPC

Messaging API for inter process communication. More...

Detailed Description

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. The content can either be provided as a 32-bit integer or a pointer.

Some message types are predefined; for example, GNRC_NETAPI_MSG_TYPE_RCV & co are defined. These are fixed in the sense that registering for a particular set of messages (for the above, e.g. gnrc_netreg_register) will use these message types. Threads that do nothing to receive such messages can safely use the same numbers for other purposes. The predefined types use non-conflicting ranges (e.g. 0x02NN) to avoid ruling out simultaneous use of different components in the same thread.

In general, threads may consider it an error to send them a message they did not request. Best practice is to log (but otherwise ignore) unexpected messages.

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_send() or msg_receive() respectively.

Additionally, one can use 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_reply() to reply to the message of the sender thread.

#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;
}
int msg_send_receive(msg_t *m, msg_t *reply, kernel_pid_t target_pid)
Send a message, block until reply received.
int msg_reply(msg_t *m, msg_t *reply)
Replies to a message.
int msg_receive(msg_t *m)
Receive a message.
int16_t kernel_pid_t
Unique process identifier.
Definition sched.h:139
kernel_pid_t thread_create(char *stack, int stacksize, uint8_t priority, int flags, thread_task_func_t task_func, void *arg, const char *name)
Creates a new thread.
#define printf(...)
A wrapper for the printf() function that passes arguments through unmodified, but fails to compile if...
Definition stdio.h:60
Adds include for missing inttype definitions.
stdio wrapper to extend the C libs stdio
Describes a message object which can be sent between threads.
Definition msg.h:196
union msg_t::@1 content
Content of the message.
uint32_t value
Value content field.
Definition msg.h:202
#define THREAD_STACKSIZE_DEFAULT
A reasonable default stack size that will suffice most smaller tasks.
#define THREAD_PRIORITY_MAIN
Priority of the main thread.

Non-blocking IPC

For the non-blocking variant use msg_try_send() or 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_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_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.

#include <inttypes.h>
#include <stdio.h>
#include "msg.h"
#include "thread.h"
#define RCV_QUEUE_SIZE (8)
static kernel_pid_t rcv_pid;
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;
}
void msg_init_queue(msg_t *array, int num)
Initialize the current thread's message queue.
int msg_try_send(msg_t *m, kernel_pid_t target_pid)
Send a message (non-blocking).
#define THREAD_EXTRA_STACKSIZE_PRINTF
Size of the task's printf stack in bytes.

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.

Files

file  msg.h
 Messaging API for inter process communication.
 
file  msg_bus.h
 Messaging Bus API for inter process message broadcast.
 

Data Structures

struct  msg_t
 Describes a message object which can be sent between threads. More...
 

Macros

#define KERNEL_PID_ISR   (KERNEL_PID_LAST + 1)
 Value of msg_t::sender_pid if the sender was an interrupt service routine.
 
#define CONFIG_MSG_QUEUE_PRINT_MAX   16U
 Number of messages to be maximally printed through msg_queue_print.
 

Functions

int msg_send (msg_t *m, kernel_pid_t target_pid)
 Send a message (blocking).
 
int msg_try_send (msg_t *m, kernel_pid_t target_pid)
 Send a message (non-blocking).
 
int msg_send_to_self (msg_t *m)
 Send a message to the current thread.
 
int msg_send_int (msg_t *m, kernel_pid_t target_pid)
 Send message from interrupt.
 
static int msg_sent_by_int (const msg_t *m)
 Test if the message was sent inside an ISR.
 
int msg_receive (msg_t *m)
 Receive a message.
 
int msg_try_receive (msg_t *m)
 Try to receive a message.
 
int msg_send_receive (msg_t *m, msg_t *reply, kernel_pid_t target_pid)
 Send a message, block until reply received.
 
int msg_reply (msg_t *m, msg_t *reply)
 Replies to a message.
 
int msg_reply_int (msg_t *m, msg_t *reply)
 Replies to a message from interrupt.
 
unsigned msg_avail_thread (kernel_pid_t pid)
 Check how many messages are available (waiting) in the message queue of a specific thread.
 
unsigned msg_avail (void)
 Check how many messages are available (waiting) in the message queue.
 
unsigned msg_queue_capacity (kernel_pid_t pid)
 Get maximum capacity of a thread's queue length.
 
void msg_init_queue (msg_t *array, int num)
 Initialize the current thread's message queue.
 
void msg_queue_print (void)
 Prints the message queue of the current thread.
 

Macro Definition Documentation

◆ CONFIG_MSG_QUEUE_PRINT_MAX

#define CONFIG_MSG_QUEUE_PRINT_MAX   16U

Number of messages to be maximally printed through msg_queue_print.

Definition at line 418 of file msg.h.

◆ KERNEL_PID_ISR

#define KERNEL_PID_ISR   (KERNEL_PID_LAST + 1)

Value of msg_t::sender_pid if the sender was an interrupt service routine.

Definition at line 262 of file msg.h.

Function Documentation

◆ msg_avail()

unsigned msg_avail ( void  )

Check how many messages are available (waiting) in the message queue.

Returns
Number of messages available in our queue on success
0, if no caller's message queue is initialized

◆ msg_avail_thread()

unsigned msg_avail_thread ( kernel_pid_t  pid)

Check how many messages are available (waiting) in the message queue of a specific thread.

Parameters
[in]pida PID
Returns
Number of messages available in queue of pid on success
0, if no caller's message queue is initialized

◆ msg_init_queue()

void msg_init_queue ( msg_t array,
int  num 
)

Initialize the current thread's message queue.

Precondition
num MUST BE A POWER OF TWO!
Parameters
[in]arrayPointer to preallocated array of msg_t structures, must not be NULL.
[in]numNumber of msg_t structures in array. MUST BE POWER OF TWO!

If array resides on the stack, the containing stack frame must never be left, not even if it is the current thread's entry function.

◆ msg_queue_capacity()

unsigned msg_queue_capacity ( kernel_pid_t  pid)

Get maximum capacity of a thread's queue length.

Returns
Number of total messages that fit in the queue of pid on success
0, if no caller's message queue is initialized

◆ msg_queue_print()

void msg_queue_print ( void  )

Prints the message queue of the current thread.

Note
Prints at most CONFIG_MSG_QUEUE_PRINT_MAX messages.

◆ msg_receive()

int msg_receive ( msg_t m)

Receive a message.

This function blocks until a message was received.

Parameters
[out]mPointer to preallocated msg_t structure, must not be NULL.
Returns
1, Function always succeeds or blocks forever.

◆ msg_reply()

int msg_reply ( msg_t m,
msg_t reply 
)

Replies to a message.

Sender must have sent the message with msg_send_receive().

Parameters
[in]mmessage to reply to, must not be NULL.
[out]replymessage that target will get as reply, must not be NULL.
Returns
1, if successful
-1, on error

◆ msg_reply_int()

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
[in]mmessage to reply to, must not be NULL.
[out]replymessage that target will get as reply, must not be NULL.
Returns
1, if successful
-1, on error

◆ msg_send()

int msg_send ( msg_t m,
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
[in]mPointer to preallocated msg_t structure, must not be NULL.
[in]target_pidPID of target thread
Returns
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)

◆ msg_send_int()

int msg_send_int ( msg_t m,
kernel_pid_t  target_pid 
)

Send message from interrupt.

Will be automatically chosen instead of msg_send() if called from an interrupt/ISR.

The value of m->sender_pid is set to KERNEL_PID_ISR.

See also
msg_sent_by_int()
Parameters
[in]mPointer to preallocated msg_t structure, must not be NULL.
[in]target_pidPID of target thread.
Returns
1, if sending was successful
0, if receiver is not waiting and block == 0
-1, on error (invalid PID)

◆ msg_send_receive()

int msg_send_receive ( msg_t m,
msg_t reply,
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. The responding thread must use msg_reply().

Any incoming messages other than the reply are put into the queue (if one is configured), block the sender (if sent with msg_send from a thread), or rejected (if sent with msg_try_send or from an interrupt) – just like if the thread were blocked on anything different than message reception.

Precondition
target_pid is not the PID of the current thread.
Parameters
[in]mPointer to preallocated msg_t structure with the message to send, must not be NULL.
[out]replyPointer to preallocated msg. Reply will be written here, must not be NULL. Can be identical to m.
[in]target_pidThe PID of the target process
Returns
1, if successful.

◆ msg_send_to_self()

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 if target_pid == thread_pid. This function never blocks.

Parameters
mpointer to message structure
Returns
1 if sending was successful
0 if the thread's message queue is full (or inexistent)

◆ msg_sent_by_int()

static int msg_sent_by_int ( const msg_t m)
inlinestatic

Test if the message was sent inside an ISR.

See also
msg_send_int()
Parameters
[in]mThe message in question.
Returns
== 0 if not sent by an ISR
!= 0 if sent by an ISR

Definition at line 291 of file msg.h.

◆ msg_try_receive()

int msg_try_receive ( msg_t m)

Try to receive a message.

This function does not block if no message can be received.

Parameters
[out]mPointer to preallocated msg_t structure, must not be NULL.
Returns
1, if a message was received
-1, otherwise.

◆ msg_try_send()

int msg_try_send ( msg_t m,
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
[in]mPointer to preallocated msg_t structure, must not be NULL.
[in]target_pidPID of target thread
Returns
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)