7.5.2 Private Buffers
Using private buffers, on the other hand, requires enough reserved memory area for the full capacity of every message queue that will be created. This approach clearly uses up more memory; however, it also ensures that messages do not get overwritten and that room is available for all messages, resulting in better reliability than the pool approach.
7.6 Typical Message Queue Operations
Typical message queue operations include the following:
· creating and deleting message queues,
· sending and receiving messages, and
· obtaining message queue information.
7.6.1 Creating and Deleting Message Queues
Message queues can be created and deleted by using two simple calls, as shown in Table 7.1.
Table 7.1: Message queue creation and deletion operations.
Operation | Description |
---|---|
Create | Creates a message queue |
Delete | Deletes a message queue |
When created, message queues are treated as global objects and are not owned by any particular task. Typically, the queue to be used by each group of tasks or ISRs is assigned in the design.
When creating a message queue, a developer needs to make some initial decisions about the length of the message queue, the maximum size of the messages it can handle, and the waiting order for tasks when they block on a message queue.
Deleting a message queue automatically unblocks waiting tasks. The blocking call in each of these tasks returns with an error. Messages that were queued are lost when the queue is deleted.
7.6.2 Sending and Receiving Messages
The most common uses for a message queue are sending and receiving messages. These operations are performed in different ways, some of which are listed in Table 7.2.
Table 7.2: Sending and receiving messages.
Operation | Description |
---|---|
Send | Sends a message to a message queue |
Receive | Receives a message from a message queue |
Broadcast | Broadcasts messages |
When sending messages, a kernel typically fills a message queue from head to tail in FIFO order, as shown in Figure 7.4. Each new message is placed at the end of the queue.
Figure 7.4: Sending messages in FIFO or LIFO order.
Many message-queue implementations allow urgent messages to go straight to the head of the queue. If all arriving messages are urgent, they all go to the head of the queue, and the queuing order effectively becomes last-in/first-out (LIFO). Many message-queue implementations also allow ISRs to send messages to a message queue. In any case, messages are sent to a message queue in the following ways:
· not block (ISRs and tasks),
· block with a timeout (tasks only), and
· block forever (tasks only).
At times, messages must be sent without blocking the sender. If a message queue is already full, the send call returns with an error, and the task or ISR making the call continues executing. This type of approach to sending messages is the only way to send messages from ISRs, because ISRs cannot block.
Most times, however, the system should be designed so that a task will block if it attempts to send a message to a queue that is full. Setting the task to block either forever or for a specified timeout accomplishes this step. (Figure 7.5). The blocked task is placed in the message queue’s task-waiting list, which is set up in either FIFO or priority-based order.
Figure 7.5: FIFO and priority-based task-waiting lists.
In the case of a task set to block forever when sending a message, the task blocks until a message queue element becomes free (e.g., a receiving task takes a message out of the queue). In the case of a task set to block for a specified time, the task is unblocked if either a queue element becomes free or the timeout expires, in which case an error is returned.
As with sending messages, tasks can receive messages with different blocking policies-the same way as they send them-with a policy of not blocking, blocking with a timeout, or blocking forever. Note, however, that in