Wednesday, August 14, 2013

Data Queue Vs MailBox: Send data

① Difference between sending data over data queue and mail box

Data Queue has fixed size data storage. So, count also is maintained. And, if there is waiting task at receive side, wake up procedure needs to be executed. If the queue is full, the task calling this function will go waiting. So, waiting procedure (priority based) needs to be executed. If both cases are not there, the data needs to be just put in the queue.

Consider one more special case "Forced Send" in Data Queue. Forced send neither wait for receive task to pass the data (synchronous message passing) nor wait for the data queue to get empty space. If queue is full, it will release one element at the head as if the data is read and data is added at the tail. This function can be used at Task context, Timer handler contexts and Interrupt handlers where snd_dtq can be used only at task contexts. See the implementation at ④. Between, ifsnd_dtq cannot be used at Task context.
 
In mail box, if there is no receive waiting task, the message will be queued in priority order. Otherwise, one wake up procedure to pass this message. Receive task will be waiting in priority order. Both Receive task and message have priority.
 
② ITRON implementation of sending data over data queue

ER snd_dtq(ID dtqid, VP_INT data)
{
        Sanity check on arguments
        Enter critical section (Interrupt Disable)
        If (count of valid data in queue == 0){
                /* then some tasks may be waiting. can pass directly */
                Check head of receive wait queue
                If there is valid task id {
                        Get the pointer to store data from task's context and store the data;
                        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
                                        return error code from scheduler
                                } else {
                                        Exit critical section and return error code from it (E_OK)
                                        (return E_OK)
                                }
                        } else {
                                Just delete the task from the receive wait queue
                                Exit critical section and return the error code from it (E_OK)
                                (return E_OK)
                        }
                }
        }
        If (count of valid data in queue reached maximum count) {
                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 for send wait queue, Check for Timeout'
                } else (Wait forever) {
                        Set TCB flags that 'Waiting forever for send wait queue'
                }
                Set data queue ID in TCB
                Store the data in context
                Select Queue according to queueing order
                If (Tasks should be granted in FIFO order)
                        Select send wait queue->Queue[0] as Queue
                Else (Should be granted in Priority order)
                        Select send wait queue->Queue[Current Tasks Priority]
                Change the task from ReadyQueue to the Data queue's send 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)
        } else {
                Store the data at the tail pointer
                Increment count for valid data
                Update the tail pointer
                if the tail pointer reached end of data queue
                        Wrap it to start of data queue
        }
        Exit critical section and return the error code from it (E_OK)
        return E_OK;
}

③ ITRON implementation of sending data over mail box

ER snd_mbx(ID mbxid, T_MSG *pk_msg)
{
        Sanity check on arguments
        Enter critical section (Interrupt Disable)
        /* Check some tasks may be waiting. can pass message directly */
        for (each receive wait queue of all priority till tail is reached){
                Check head of receive wait queue
                If there is valid task id {
                        Get the pointer to store message from task's context and store the message pointer;
                        if task is waiting in Timeout
                                remove from timer queue
                        Set task status ad 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
                                        return error code from scheduler
                                } else {
                                        Exit critical section and return error code from it (E_OK)
                                        (return E_OK)
                                }
                        } else {
                                Just delete the task from the receive wait queue
                                Exit critical section and return the error code from it (E_OK)
                                (return E_OK)
                        }
                }
        }
        Take message queue head;
        if (message priority level is more than 1)
                Get the message queue head corresponding to that priority;
        /* Add the message to the tail of the list pointed by the queue head */
        if queue head points to NULL
                queue head = message;
        else
                queue tail->next = message;
        Update the queue tail too to point message;
        message -> next = NULL;
        Exit critical section and return the error code from it (E_OK)
        return E_OK;
}

④ ITRON implementation to forcefully send data in Data Queue

ER fsnd_dtq(ID dtqid, VP_INT data)
{
        Sanity check on arguments
        Enter critical section (Interrupt Disable)
        Check receive queue head;
        if (there is no waiting receive tasks in the queue)
        {
                take the task at the head of the queue;
                assign the data to this waiting task through context;
                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
                                return error code from scheduler
                        } else {
                                Exit critical section and return error code from it (E_OK)
                                (return E_OK)
                        }
                } else {
                        Just delete the task from the receive wait queue
                        Exit critical section and return the error code from it (E_OK)
                        (return E_OK)
                }
        }
        if (count of data in queue == size of data queue (queue is full))
        {
                Dummy read (scrap) data at the head of queue (advance read pointer);
                /* to free space for this new data; count won't change and this is just going to occupy */
        }
        else {
                increment the data count;
        }
        add the data at the write pointer (tail of queue);
        update the write pointer;
        Exit critical section and return the error code from it (E_OK)
        return E_OK;
}

See you in other RTOS posts..

No comments: