Saturday, December 14, 2013

Message Buffer Vs Data Queue: Receive message

① Implementation difference between Message buffer receive and Data queue Receive

Data queue is based on single data element reception. So, when some sending tasks are waiting, at the end of this function, just one taks at the head of the send-waiting queue is allowed to use the space to store the data. But, Message Buffer is based on variable length messages. So, when using the emptied space, all the tasks till the send-wait queue is emptied or the placing of the message fails is carried out.
 
Remember this API returns the message length received. No other APIs except Send Message buffer, Receive Message Buffer and some APIs in rendezvous returns a non-zero data in between scheduling (as a blocking call).

cre_xxx returns the Non-zero value, but it never blocks. Zero message length and messages with more length of the buffer are nothing to do with this system call. Because, when these are found in snd_mbf, error is returned.

② ITRON implementation of receiving message buffer

ER rcv_mbf(ID mbfid, VP msg)
{
        Sanity check on arguments
        Enter critical section (Interrupt Disable)
        /* First check about the buffer empty condition */
        if (buffer is empty == 0) {
                /* If free, check send task queue for synchronous message passing */
                Check send task waiting queue;
                if (some send task is waiting) {
                        /* Copy the message to the send task's buffer */
                        Get the size of message from task's context and if not zero {
                                Get the pointer to message from task's context and copy the message from;
                        }
                        /* Wakeup procedure for send tasks */
                         if task is waiting in Timeout
                                 remove from timer queue
                         Set task status as Ready
                         if the task is NOT suspended {
                                 Change the task to the Ready Queue of priority
                                 If (the task priority is higher than the current){
                                         call scheduler
                                         /* Execution will return here */
                                         return the message size
                                 } else {
                                         Exit critical section and return message size
                                 }
                         } else {
                                 Just delete the task from the send wait queue
                                 Exit critical section and return message size
                         }
                }
                /* No waiting send tasks. This function needs to aquire the message buffer from
                    the buffer. But, the buffer is empty. So, this function needs to wait. */
                /* No data, no sending task, so got to waiting */
                If (polling mode)
                        Exit critical section and return E_TMOUT;
                If (this function is called from interrupt context) or
                If (called from task independent state ex: timer handlers) or
                If (called from dispatch disabled state)
                        Return E_CTX;
                If (Timeout value is specified) {
                        Add task into timer queue;
                        Set TCB flags that 'Waiting in message buffer receive wait queue, Check for Timeout'
                } else (Wait forever) {
                        Set TCB flags that 'Waiting forever in message buffer receive wait queue'
                }
                Set data queue ID in TCB
                Store the buffer pointer in context
                Change the task from ReadyQueue to the Data queue's receive wait Queue
                Schedule the tasks, since this task is going to sleep
                (Once the task is released, execution will return here)
                Return the value set by scheduler(Scheduler directly set return value before return here)
                /* When this task is waken up, the message size will be set in error code register */
        }
        /* Some data is in the message buffer. Just receive it */
        If (maximum message size is 1) {
                Just copy single bytes. /* There is
                any other management data is not needed inside the buffer. */
                Read the data and place on this function's message buffer;
                Increment the free buffer size;
                Adjust the read pointer;
                Remember the length;
        } else {
                Read length byte by byte
                Increment the free buffer size
                Copy the message by taking consideration of that it might have been wrapped.
                Remember the size;
        }
        /* check for send tasks waiting for to get free space in queue */
        /* check for some free space in buffer. Now, the sending tasks needs to be
           checked to push the data into the buffer */
        Check send task waiting queue;
        for (every send task that is waiting in each priority level) {
                take the message size from the task's context;
                take the message data from the task's context;
                if (discovered zero length message size) {
                        break;
                } else {
                        Try to copy the message into the buffer;
                        if (copy failed)
                                break;
                }
                /* Data is placed in the buffer. So, wakeup processing. */
                if task is waiting in Timeout
                         remove from timer queue
                Set task status as Ready
                if the task is NOT suspended {
                        Change the task to the Ready Queue of priority
                        If (the task priority is higher than the current){
                                set flag that scheduler needs to be called
                        }                        }
                } else {
                        Just delete the task from the send wait queue
                }
        }
        if (flag is set) {
                call scheduler
                return the remembered length;
        }
        Exit critical section and return the remembered length;
}
 

No comments: