Data is passed through a message buffer by copy - the data is copied into the buffer by the sender and out of the buffer by the read.
Unlike most other FreeRTOS communications primitives, stream buffers, and therefore also message buffers, are optimised for single reader single writer scenarios, such as passing data from an interrupt service routine to a task, or from one microcontroller core to another on a dual core CPU.
Message buffer functionality is enabled by including the FreeRTOS/source/stream_buffer.c source file in the build.
The message buffer implementation uses direct to task notifications. Therefore, calling a message buffer API function that places the calling task into the Blocked state can change the calling task's notification state and value.
IMPORTANT NOTE: Uniquely among FreeRTOS objects, the stream buffer implementation (so also the message buffer implementation, as message buffers are built on top of stream buffers) assumes there is only one task or interrupt that will write to the buffer (the writer), and only one task or interrupt that will read from the buffer (the reader). It is safe for the writer and reader to be different tasks or interrupts, but, unlike other FreeRTOS objects, it is not safe to have multiple different writers or multiple different readers. If there are to be multiple different writers then the application writer must place each call to a writing API function (such as xStreamBufferSend()) inside a critical section and use a send block time of 0. Likewise, if there are to be multiple different readers then the application writer must place each call to a reading API function (such as xStreamBufferReceive()) inside a critical section and use a receive block time of 0.
See the message buffer section of the user documentation for a list of message buffer related API functions, in many cases including code snippets that demonstrate the functions being used.
If a non zero block time is specified when a task uses xMessageBufferReceive() to read from a message buffer that happens to be empty the task will be placed into the Blocked state (so it is not consuming any CPU time and other tasks can run) until either data becomes available in the message buffer, or the block time expires.
If a non zero block time is specified when a task uses xMessageBufferSend() to write to a message buffer that happens to be full the task will be placed into the Blocked state (so it is not consuming any CPU time and other tasks can run) until either space becomes available in the message buffer, or the block time expires.