Allocating a Message
MessageQ manages message allocation via the MessageQ_alloc() and MessageQ_free() functions. MessageQ uses Heaps for message allocation. MessageQ_alloc() has the following syntax: MessageQ_Msg MessageQ_alloc(UInt16 heapId, UInt32 size);
The allocation size in MessageQ_alloc() must include the size of the message header, which is 32 bytes. The following code allocates a message: #define MSGSIZE 256#define HEAPID 0...MessageQ_Msg msg; ... msg = MessageQ_alloc(HEAPID, sizeof(MessageQ_MsgHeader));if (msg == NULL) { System_abort("MessageQ_alloc failed\n");}
Once a message is allocated, it can be sent on any message queue. Once the reader receives the message, it may either free the message or re-use the message.
Messages in a message queue can be of variable length. The only requirement is that the first field in the definition of a message must be a MsgHeader structure. For example: typedef struct MyMsg { MessageQ_MsgHeader header; // Required SomeEnumType type // Can be any field ... // ...} MyMsg;
The MessageQ APIs use the MessageQ_MsgHeader internally. Your application should not modify or directly access the fields in the MessageQ_MsgHeader structure. MessageQ Allocation and HeapsAll messages sent via the MessageQ module must be allocated from a xdc.runtime.IHeap implementation, such as ti.sdo.ipc.heaps.HeapBufMP. The same heap can also be used for other memory allocation not related to MessageQ. The MessageQ_registerHeap() API assigns a MessageQ heapId to a heap. When allocating a message, the heapId is used, not the heap handle. The heapIds should start at zero and increase. The maximum number of heaps is determined by the numHeap module configuration property. See the online documentation for MessageQ_registerHeap() for details. /* Register this heap with MessageQ */status = MessageQ_registerHeap( HeapBufMP_Handle_upCast(heapHandle), HEAPID);
If the registration fails (for example, the heapId is already used), this function returns FALSE. An application can use multiple heaps to allow an application to regulate its message usage. For example, an application can allocate critical messages from a heap of fast on-chip memory and non-critical messages from a heap of slower external memory. Additionally, heaps MessageQ uses can be shared with other modules and/or the application. MessageQ alternatively supports allocating messages without the MessageQ_alloc() function. Heaps can be unregistered via MessageQ_unregisterHeap(). MessageQ Allocation Without a HeapIt is possible to send MessageQ messages that are allocated statically instead of being allocated at run-time via MessageQ_alloc(). However the first field of the message must still be a MsgHeader. To make sure the MsgHeader has valid settings, the application must call MessageQ_staticMsgInit(). This function initializes the header fields in the same way that MessageQ_alloc() does, except that it sets the heapId field in the header to the MessageQ_STATICMSG constant. If an application uses messages that were not allocated using MessageQ_alloc(), it cannot free the messages via the MessageQ_free() function, even if the message is received by a different processor. Also, the transport may internally call MessageQ_free() and encounter an error. If MessageQ_free() is called on a statically allocated message, it asserts that the heapId of the message is not MessageQ_STATICMSG. Sending a MessageOnce a message queue is opened and a message is allocated, the message can be sent to the MessageQ via the MessageQ_put() function, which has the following syntax. Int MessageQ_put(MessageQ_QueueId queueId, MessageQ_Msg msg);
For example:
status = MessageQ_put(remoteQueueId, msg);
Opening a queue is not required. Instead the message queue ID can be "discovered" via the MessageQ_getReplyQueue() function, which returns the 32-bit queueId. MessageQ_QueueId replyQueue;MessageQ_Msg msg; /* Use the embedded reply destination */replyMessageQ = MessageQ_getReplyQueue(msg);if (replyMessageQ == MessageQ_INVALIDMESSAGEQ) { System_abort("Invalid reply queue\n");} /* Send the response back */status = MessageQ_put(replyQueue, msg); if (status < 0) { System_abort("MessageQ_put was not successful\n"); }
If the destination queue is local, the message is placed on the appropriate priority linked list and the ISync signal function is called. If the destination queue is on a remote processor, the message is given to the proper transport and returns. If MessageQ_put() succeeds, it returns MessageQ_S_SUCCESS. If MessageQ_E_FAIL is returned, an error occurred and the caller still owns the message. There can be multiple senders to a single message queue. MessageQ handles the thread safety. Before you send a message, you can use the MessageQ_setMsgId() function to assign a numeric value to the message that can be checked by the receiving thread. /* Increment...the remote side will check this */msgId++;MessageQ_setMsgId(msg, msgId);
You can use the MessageQ_setMsgPri() function to set the priority of the message.
Receiving a MessageTo receive a message, a reader thread calls the MessageQ_get() API. Int MessageQ_get(MessageQ_Handle handle, MessageQ_Msg *msg, UInt timeout)
If a message is present, it returned by this function. In this case the ISync's wait() function is not called.
For example: /* Get a message */status = MessageQ_get(messageQ, &msg, MessageQ_FOREVER);if (status < 0) { System_abort("Should not happen; timeout is forever\n");}
If no message is present and no error occurs, this function blocks while waiting for the timeout period for the message to arrive. If the timeout period expires, MessageQ_E_FAIL is returned. If an error occurs, the msg argument will be unchanged. After receiving a message, you can use the following APIs to get information about the message from the message header: - MessageQ_getMsgId() gets the ID value set by MessageQ_setMsgId(). For example:
/* Get the id and increment it to send back */ msgId = MessageQ_getMsgId(msg); msgId += NUMCLIENTS; MessageQ_setMsgId(msg, msgId);
- MessageQ_getMsgPri() gets the priority set by MessageQ_setMsgPri().
- MessageQ_getMsgSize() gets the size of the message in bytes.
- MessageQ_getReplyQueue() gets the ID of the queue provided by MessageQ_setReplyQueue().
Deleting a MessageQ ObjectMessageQ_delete() frees a MessageQ object stored in local memory. If any messages are still on the internal linked lists, they will be freed. The contents of the handle are nulled out by the function to prevent use after deleting. Void MessageQ_delete(MessageQ_Handle *handle);
The queue array entry is set to NULL to allow re-use. Once a message queue is deleted, no messages should be sent to it. A MessageQ_close() is recommended, but not required. Message PrioritiesMessageQ supports three message priorities as follows: - MessageQ_NORMALPRI = 0
- MessageQ_HIGHPRI = 1
- MessageQ_URGENTPRI = 3
You can set the priority level for a message before sending it by using the MessageQ_setMsgPri() function: Void MessageQ_setMsgPri(MessageQ_Msg msg, MessageQ_Priority priority)
Internally a MessageQ object maintains two linked lists: normal and high-priority. A normal priority message is placed onto the "normal" linked list in FIFO manner. A high priority message is placed onto the "high-priority" linked list in FIFO manner. An urgent message is placed at the beginning of the high linked list. NOTE
Since multiple urgent messages may be sent before a message is read, the order of urgent messages is not guaranteed.
When getting a message, the reader checks the high priority linked list first. If a message is present on that list, it is returned. If not, the normal priority linked list is checked. If a message is present there, it is returned. Otherwise the synchronizer's wait function is called. NOTE
The MessageQ priority feature is enabled by the selecting different MessageQ transports. Some MessageQ implementations (e.g. Linux) may not support multiple transports and therefore may not support this feature.
|