Monday, February 24, 2014

Task Management: Just Exit Vs Exit and delete

① Exiting Task

The aeroplane went down for landing. After touched down the runway, it got signal to lift off, and it took off. Exiting task does the same. It resets all the TCB parameters. And, if there is pending activation requests, it starts the task freshly. But, remember that it is removed from Ready queue and added again to maintain the order of activation (precedence) of tasks which are in the same priority. Also remember that the scheduling is done without saving the context of the executing task since it is assumed to exit and no more existing.
Remember one more important thing. The task is not deleted. It should be able to be activated again. So, the TCB is needed to be brought back to the state of after task creation. Especially, the parameters passed by the user in cre_tsk() need to be restored. All allocated items are kept as it is.

② Exiting and Deleting task

Just releasing the resources and calling scheduler not to save current context, but only schedule others. Remember the scheduler (dispatcher) itself acts as unlocking of critical section. It unlocks the critical section before getting scheduled to any other execution point. Whether all calls to the dispatcher has the critical section locked needs to be checked. Otherwise, the masking of interrupt level itself is considered as masking of execution of dispatcher. Masking of any interrupt level just above the task level will cause the dispatcher not to be scheduled and always return to the same task.

The precedence is as follows as per specification.
Precedence:
1) Interrupt Handlers, time event handlers, CPU exception handlers
2) Dispatcher (one of the kernel processes) (Assume this Highest priority task) - Interrupt Level 16
3) Tasks - Interrupt Level 16
③ uITRON implementation of ext_tsk

void ext_tsk(void)
{
        If the called from ISR or Dispatch disabled state or from dispatcher
                return E_CTX;
        Enter critical section
        Take the TCB
        Reset the task priority and base priority to what user had set initially
        if there is taks exception handler defined {
                clear the pending exception pattern
                Disable the exception handling
                Reset backup of task context to NULL, since it is no more going to be used
                /* Hopefully the backup context is not referred, if this is called from
                   inside exception handler */
        }
        Remove the tcb from the Ready queue (it should be in ready queue)
        If (it is holding any mutex) {
                unlock all mutexes as specified below
                set the head pointer to the locked mutex as NULL
        }
        if (there are pending activation requests) {
                Reduce the count by one
                /* Same as sta_tsk and act_tsk. But, one difference is here, you
                   cut the tree on which you are sitting on. You are going to edit the
                   context of yours which exists on the same stack space where the
                   program itself is running. So, atleast you have to make sure that
                   the stack pointer is apart from the context area */
                Set the initial context just above the bottom of the stack
                call assembly routine to reset the stack pointer to just above the context
                /* context initialization same as of sta_tsk, act_tsk */
                context's argument register = stacd
                Initialize context's Link register (return address) = ext_tsk function
                According to task attributes such as enabled FPU,
                        Initialize/Enabling of the FPU related registers
                Initialize program status register
                context's program counter = task start address;
                Initialize other values and counts of the context;
                status = READY;
                wake-up and suspend count and overrun count = 0;
                Add the task to the Ready Queue of priority
                /* Anyway, the scheduler will be called */
                call scheduler not to save current context, but only schedule others
                /* It No more returns here */
        }
        status = DORMANT;
        call scheduler not to save current context, but only schedule others
        /* It No more returns here */
}

void unlock_all_mutexes()
{
        /* Parse through all mutexes locked by the task */
        Take the first mutex locked by the Task
        while (there is mutex locked by the task) {
                Keep the next mutex linked to this mutex (belongs to the same task)
                Isolate(unlink) this mutex by setting the next field to zero
                /* Grant this mutex to one waiting task and wake it up */
                For all tasks waiting in this mutex's queue (from head having highest priority tasks) {
                        Take a task.
                        If it is waiting as Timeout, remove it from timer queue
                        Remove the task from the mutex's queue
                        Set tcb status as Ready
                        /* Sanity check and lock assignment as if it called loc_mtx */
                        If the mutex attribute is Ceiling and the task has higher base priority {
                        /* When ths task is waiting, base priority is changed by chg_pri() */
                                Error code parameter of tcb = E_ILUSE
                                Add the task to the Ready queue
                                If the task's priority is higher than the current task's priority
                                        Set to call scheduler when quitting this function
                                Take next task and continue checking from first
                        } else {
                                If the mutex has CEILING attribute and
                                the ceiling priority is higher than the task priority{
                                        the task (tcb) priority is set to the ceiling priority
                                } else {
                                        the task's priority is set as current highest
                                            priority locking the mutex
                                }
                                Set the task as locking task
                                Add the mutex in the task's queue of mutexes
                                If the task's priority is higher than the current task's priority
                                        Set to call scheduler when quitting this function
                        }
                }
                Assign the next mutex as this mutex
        }
}

④ uITRON implementation of exd_tsk()

void exd_tsk(void)
{
        Enter critical section
        Take the TCB
        Remove the tcb from the Ready queue (it should be in ready queue)
        If (it is holding any mutex) {
                unlock all mutexes as specified in ext_tsk()
        }
        Release the memory allocated for any element in TCB
        /* Bring back the task to non-existent state so that the task entry can be allocated to any other task */
        Assigning NULL to the task entry etc.
        call scheduler not to save current context, but only schedule others
        /* It No more returns here */
}

Unexpectedly Exiting and Deleting is easier than just exiting..

No comments: