Messages are the unit of communication in an appCORE application. Messages can be created and duplicated, then dispatched or broadcast to other threads. A message that is dispatched to a thread becomes an input message for that thread and can be forwarded on to other threads, without being copied. When their work is done, messages are either returned to the heap, or returned to the message pool, depending on the configuration. For input messages, appCORE handles freeing or forwarding the message, after the user's message handler unwinds.

The only two (2) explicit ways to create a message in appCORE are via the coreMsgCreate() and coreMsgDup() functions. Valid user message types are between 0 and 0x7fff000. Messages types equal and above 0x7fff000 are reserved by appCORE. The following code snippet illustrates creating an empty message of message type one (1) and duplicating that message. Both messages are later freed as we did not dispatch either message. Error checking is omitted for clarity.

#include "appcore.h"

coreMsg_t* pMsg1;
coreMsg_t* pMsg2;
    .
    pMsg1 = coreMsgCreate( 1, 0, NULL );
    pMsg2 = coreMsgDup( pMsg1 );
    .
    coreMsgFree( pMsg1 );
    coreMsgFree( pMsg2 );
    .

In appCORE the term to 'dispatch' a message means to put the message on another thread's input queue immediately. Only a message that has been created or duplicated can be dispatched. It can not be forwarded - only input messages can be forwarded.

The following code snippet illustrates creating an empty message of message type one (1) and dispatching it to another thread. After the function returns the message is owned by the destination thread and must not be accessed by the sending thread. It is good practice to null the message pointer after dispatching the message to avoid later access.

#include "appcore.h"

corehTHR_t hThr2 = ...;
coreMsg_t* pMsg;
    .
    pMsg = coreMsgCreate( 1, 0, NULL );
    coreMsgDispatch( hThr2, pMsg );
    pMsg = NULL;
    .

In appCORE the term to 'forward' a message means to mark the thread's current input message to be forwarded on to another thread after the user's message handler function unwinds. The purpose of this function is to allow an input message to be passed to another thread in an efficient, thread safe manner. The message is not copied and is never accessible by more then one (1) thread at a time. Forwarding a message to a multicore block is also allowed via the coreMultiCoreForward() function.

The following code snippet illustrates a simple message handler function. Message type one (1) is forwarded to thread hThr2 and message type two (2) is forwarded to the multicore block hMCore1. When the MsgHandler unwinds, appCORE will forward the message to the designated thread instead of freeing the message. Error handling is omitted for clarity.

#include "appcore.h"

int MsgHandler( void* Cntxt, coreMsg_t* pMsg )
{
corehTHR_t   hThr2 = ...;
corehMCore_t hMCore1 = ...;

    switch( CORE_MSG_TYPE( pMsg ) )
    {
    case 1: coreMsgForward( hThr2, pMsg ); break;
    case 2: coreMultiCoreForward( hMCore1, pMsg ); break;
    .
    .
    }

    return( 0 );
}

The function coreMsgBroadcast() is used to dispatch a message to all threads. Internally this function duplicates the input message for each destination thread. Because this function internally duplicates its input message, there are no restrictions on the input message. It may be either a newly created message, a duplicated message, or a thread input message.

The following code snippet illustrates creating an empty message of message type one (1) and then broadcasting it to all threads. The message is freed as the broadcast function duplicates the input message internally. Error checking is omitted for clarity.

#include "appcore.h"

coreMsg_t* pMsg;
    .
    .
    pMsg = coreMsgCreate( 1, 0, NULL );
    coreMsgBroadcast( pMsg );
    coreMsgFree( pMsg );
    .

The standard message processing steps in an appCORE message thread are as follows:
  1. appCORE waits for an input message to be pushed onto the thread's input queue.
  2. appCORE pops the message off the thread's input queue.
  3. appCORE calls the user's message handler function with the context and the message pointer.
  4. The user's message handler function processes the message.
  5. appCORE frees or forwards the message to the designated thread.
In a standard appCORE application, the user does not worry about which thread owns and frees the message memory. appCORE handles this and it is a powerful design pattern making it difficult to leak memory.

appCORE's default configuration uses a collection of message pools for efficiency and to avoid heap fragmentation. Initially, when a message is allocated, the message size if rounded up to the nearest pool size, and the message is allocated from the heap. When the message is freed, the message is not returned to the heap, but is instead put on one of the message pool free lists. Subsequent message allocation checks the appropriate message pool before allocating a new message from the heap. If a message is available on the appropriate free list, it is used. There are 11 message pools for the following message sizes, in bytes: 32, 64, 128, 256, 512, 1K, 2K, 4K, 8K, 16K, 32K, and 64K. Messages larger then 64K are always allocated from the heap and returned to the heap.

The message pool feature is enabled by default. It can be disabled via the coreSPEC_t 'coreMsgPoolOff' element passed to the coreInit() function.