Saturday, April 19, 2014

uITRON: ext_tsk vs ter_tsk

① Difference between Task exit and termination

Terminate is same as ext_tsk, but ext_tsk is suicide and ter_tsk is murder. Both will be reactivated in case there are pending requests for that particular task.

② uITRON implemenation of ter_tsk

ER ter_tsk(ID tskid)
{
        If the task itself is calling this function,
                return E_ILUSE;
        Sanity check on arguments
        Enter critical section
        Take the TCB
        If (the task is already in Dormant state) {
                Exit critical section
                return E_OBJ;
        }
        /* A lot of things need to be done */
        /* ter_tsk must be called from other tasks. So, the terminated task
            must be at lower priority. So, it must be ended by just releasing
            resources corresponding to the task and removing from the ready
            queue and making it dormant. And, just continue the execution of
            calling function. No scheduling is required unless otherwise there
            are some pending activation requests (again added in the ready queue)
            and the initial priority is higher than the calling one */
        /* But, think that there are some other special cases where this
           function is called from ISR, but the task is in Running state. This
           means the highest priority running task is getting removed from
           ready queue.
           So, rescheduling needs to be done. When called from Timer event
           handler, scheduling will be done after the handler. So, no issues.
           When this system call is called from interrupt context, just enable
           the flag that the dispatch is delayed before returning the call. */
        if (this function is called from ISR and ) {
                Enable the flag that there is pending dispatch
                /* guess here too the dispatch disable needs to be released. */
                /* Yes! this processing has some inconsistency, that the task is
                   allowed to run after removed from Ready queue and made the
                   status as Dormant. Also, the Dispatch is kept disabled. So,
                   other tasks cannot run. The use case will be when the task
                   disablesdispatch and processing something, interrupt occurs
                   and thetask is terminated from the interrupt handler. */
        }
        /* Normal processing starts here... Release all hold by the task */
        if (the terminating task has disabled the dispatch..
                /* then, ofcourse this should have been called from ISR or
                   timer handlers. (If ISR, then since dispatch is delayed,
                   this task is given time to return its execution and enable
                   the dispatch by itself, then the scheduling will be done
                   from ena_dsp.. when dispatch is disabled even ISR will not
                   reschedule) */
                ..and this system call is called from the timer handler) {
                        and the task that disabled dispatch is the terming one) {
                        Release the dispatch disable (enable).
                        /* As the timer handler is going to reschedule, all
                           system state changed by terming task needs to be
                           brought back, since the terminating one will not
                           execute again. */
                }
        }
        /* In contrary to the exit task, the terminating task may be in the
           mid of processing of kernel objects. So, every possibility of each
           kernel objects being processed in the waiting state needs to be
           considered and released properly */
        /* And also, the TCB needs to be initialized to be in the Dormant state */
        base priority of TCB = current priority = Priority assigned by user
        if (task is waiting in Timeout)
                remove from timer queue
        if ((task is in Ready state and not in suspended)
        /* Suspended task is isolated which will unlinked from all queues */
         or (queued/linked in any other object's wait queue))  {
                Just remove/unlink from the queue;
                if (the task was waiting in the Mutex queue) {
                        /* equillibrium affected */
                        balance_mtx_equillibrium();
                }
                else if (the task is waiting in the message buffer queue) {
                        check the next task in queue can send the message();
                        /* If some task advanced to the head of queue because
                           of deletion of the terming task, then there is
                           chance */
                }
                else if (the task is waiting in the variable mpool queue) {
                        check the next task in the queue can get the memory
                        /* If some task advanced to the head of queue because
                           of deletion of the terming task, then there is
                           chance */
                }
        }
        if (the task has locked mutexes) {
                unlock all mutexes; /* processes the equillibrium */
                /* but, it does not cause any task to change priority */
                set the head pointer to the list of mutexes as zero
        }
        if (task exception handler is defined) {
                /* Regardless of whether the task is in exception handler, just
                   reset the exception handler block. Note that the handler
                   block is not released. So, the pointers will be still valid
                   when the implementation refers when returning from the
                   handler. The release of task exception block needs to be done
                   by def_tex(). Whats done here is that the task's context
                   which is backed up by the tex block is nullified. This is
                   fine as the execution is never going to execute the task.
                   It is justified as follows:
                   1) If the task itself has raised the exception, then this
                      cannot be called from the task itself. If this call has
                      been called from ISR or timer handler, then rescheduling
                      will happen inside/just out of ISR/timer handler. And,
                      since the task is deleted from Ready Queue, the execution
                      will never return to the task or Exception handler.
                      Exception handler itself disappears in halfway. So, the
                      context is no more needed.
                   2) Same as above, even if the task exception is raised from
                      other task. Because, the exception is considered same as
                      the task except that the execution code block is different.
                      So, no matter whether it is task or exception handler, it
                      will be just terminated. The execution will not be back.
                      No meaning for termination otherwise.
                   */
                task exception block's task context backup pointer = NULL;
                task exception block's status = DISABLED;
                task exception block's pending patter = 0;
        }
        if (there are pending activations) {
                /* Activate the task again. Same as activate & start task */
                /* Remember in exit task too. It is activated. But, difference
                   is ext_tsk is killing myself. ter_tsk is killed by others.
                   But, activation on both cases happens there are pending
                   activation requests */
                Move to the high address of stack space (bottom);
                Assume that the context is saved in the stack, so move up one
                context size from the bottom and assign it as current stack
                pointer of the context;
                /* The contents of registers when the task begins executing are
                   not guaranteed. So, not all of the registers but few
                  important registers of the context needs to be initialized */
                /* This will be hardware dependent portion */
                /* Especially, all special purpose register value needs to be initialized */
                /* As if ext_tsk is called by default when exiting the task function, */
                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;
                context's argument register = stacd
                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
                If (the tw-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 {
                set the task status as DORMANT.
        }
        exit critical section and return error code
}


Termination - dealing with a koma patient..