Here, we are going to talk about the computation of the scheduler. As mentioned last blog, the next_wake is the essential variable that determines the next wake-up of the scheduler. So we will check where this variable is changed.
Code Segment 1 (next_wake is changed in the task scan):
for (task_ID=0; task_ID < NRK_MAX_TASKS; task_ID++){
......
if(nrk_task_TCB[task_ID].task_state == SUSPENDED){
......
if(nrk_task_TCB[task_ID].next_wakeup!=0 &&
nrk_task_TCB[task_ID].next_wakeup<next_wake )
next_wake=nrk_task_TCB[task_ID].next_wakeup;
}
}
From this segment, we conclude that next_wake is related with user-defined task's next wake-up time, since only user-defined task will have SUSPENDED task state and idle task won't. However, how's the next_wake changed?
Code Segment (in the task scanning loop)
if( nrk_task_TCB[task_ID].task_ID!=NRK_IDLE_TASK_ID &&
nrk_task_TCB[task_ID].task_state!=FINISHED ){
if(nrk_task_TCB[task_ID].next_wakeup >= _nrk_prev_timer_val)
nrk_task_TCB[task_ID].next_wakeup-=_nrk_prev_timer_val;
else
nrk_task_TCB[task_ID].next_wakeup=0;
......
}
The scenario described here by the code is that if the next_wakeup time line (which is defined initially by the nrk_create_taskset) is behind current task ending line plus 2ms, the next_wakeup time line should move forward by _nrk_prev_timer_val, otherwise, the task should be waken up immediately. Then the scheduler would execute this task soon. (Refer to last blog to see how does this happen) However this may result in unexpected bugs if the next_wakeup is smaller than _nrk_prev_timer_val but not so much. Next blog would talk about these potential bugs in the scheduler.
Code Segment 2 (next_wake is changed in non-idle and idle tasks respectively):
In next executable non-idle task
if(nrk_task_TCB[task_ID].cpu_reserve!=0 &&
nrk_task_TCB[task_ID].cpu_remaining<MAX_SCHED_WAKEUP_TIME){
if(next_wake>nrk_task_TCB[task_ID].cpu_remaining)
next_wake=nrk_task_TCB[task_ID].cpu_remaining;
}else{
if(next_wake>MAX_SCHED_WAKEUP_TIME)
next_wake=MAX_SCHED_WAKEUP_TIME;
}
Here, we know that next_wake is also related with task's cpu remaining time. First, we have to notice that task's cpu_reserve should be initialized to non-zero. And then we have to know that task_ID here is the highest priority task ID. Additionally, the next_wake here is the closest next wake-up time line. Therefore, the code segment here indicates that next wake-up time is not allowed to exceed the highest priority task's cpu remaining time. It means that if next executable task is not idle, it has to be interrupted by the scheduler at the moment that the highest priority task's cpu remaining time is consumed out. This is actually undesired wake-up and may result in unexpected bugs. Next blog would talk about these potential bugs in the scheduler.
In idle task
if(next_wake>NRK_SLEEP_WAKEUP_TIME) {
if(next_wake-NRK_SLEEP_WAKEUP_TIME
<MAX_SCHED_WAKEUP_TIME){
if(next_wake-NRK_SLEEP_WAKEUP_TIME
<NRK_SLEEP_WAKEUP_TIME)
next_wake=NRK_SLEEP_WAKEUP_TIME-1;
else
next_wake=next_wake-NRK_SLEEP_WAKEUP_TIME;
}else if(next_wake>NRK_SLEEP_WAKEUP_TIME
+MAX_SCHED_WAKEUP_TIME
next_wake=MAX_SCHED_WAKEUP_TIME;
else
next_wake=MAX_SCHED_WAKEUP_TIME
-NRK_SLEEP_WAKEUP_TIME;
}
Since idle task has the lowest priority, we don't need to worry about that some other task would preempt it. We see that next_wake has to be larger than 10ms (which is represented by NRK_SLEEP_WAKEUP_TIME), otherwise next_wake is determined by Code Segment 1. Once the condition is satisfied, the scheduler would wake up 10ms before the closest next user-defined task. (because next_wake is determined by Code Segment 1 before) Therefore, we see that idle task plays a role here in making the processor sleep deep, just as mentioned before in last blog.
Generally, the computation here includes:
1. computes all the next_wakeups of tasks and pick the closest one as the next_wake which determines the next wake-up time of the scheduler.
2. Get the highest priority task ID (task_ID).
3. (1) If the task_ID indicates a non-idle task and cpu_reserve is initialized as non-zero, next_wake is set to cpu_remaining. (2) If the task_ID indicates an idle task, next_wake is 10ms before the closest next user-defined task.
4. _nrk_set_next_wakeup(next_wake) starts next round of scheduling.
if(next_wake-NRK_SLEEP_WAKEUP_TIME
<MAX_SCHED_WAKEUP_TIME){
if(next_wake-NRK_SLEEP_WAKEUP_TIME
<NRK_SLEEP_WAKEUP_TIME)
next_wake=NRK_SLEEP_WAKEUP_TIME-1;
else
next_wake=next_wake-NRK_SLEEP_WAKEUP_TIME;
}else if(next_wake>NRK_SLEEP_WAKEUP_TIME
+MAX_SCHED_WAKEUP_TIME
next_wake=MAX_SCHED_WAKEUP_TIME;
else
next_wake=MAX_SCHED_WAKEUP_TIME
-NRK_SLEEP_WAKEUP_TIME;
}
Since idle task has the lowest priority, we don't need to worry about that some other task would preempt it. We see that next_wake has to be larger than 10ms (which is represented by NRK_SLEEP_WAKEUP_TIME), otherwise next_wake is determined by Code Segment 1. Once the condition is satisfied, the scheduler would wake up 10ms before the closest next user-defined task. (because next_wake is determined by Code Segment 1 before) Therefore, we see that idle task plays a role here in making the processor sleep deep, just as mentioned before in last blog.
Generally, the computation here includes:
1. computes all the next_wakeups of tasks and pick the closest one as the next_wake which determines the next wake-up time of the scheduler.
2. Get the highest priority task ID (task_ID).
3. (1) If the task_ID indicates a non-idle task and cpu_reserve is initialized as non-zero, next_wake is set to cpu_remaining. (2) If the task_ID indicates an idle task, next_wake is 10ms before the closest next user-defined task.
4. _nrk_set_next_wakeup(next_wake) starts next round of scheduling.