① Difference between Task exit and termination
② 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..
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..