平台:VS2010 版本:1.04
在讲解任务管理之前先看RAW-OS的就绪队列结构:
typedef struct RAW_RUN_QUEUE {
RAW_U8 highest_priority;
LIST task_ready_list[CONFIG_RAW_PRIO_MAX];
RAW_U32 task_bit_map[NUM_WORDS];
} RAW_RUN_QUEUE;
先看看RAW_RUN_QUEUE这个结构体:highest_priority指当前就绪任务的最高优先级(RAW-OS会执行优先级为highest_priority的任务);task_ready_list[CONFIG_RAW_PRIO_MAX]是就绪任务的链表,CONFIG_RAW_PRIO_MAX代表可以有多少个优先级,每个优先级都有自己的就绪任务链表;若task_bit_map(n)为1代表有优先级为n的就绪任务(n/32为task_bit_map数组的index)。这样任务调度时,RAW-OS就可以根据RAW_RUN_QUEUE来进行任务切换。
任务的管理重点就是任务的调度,那什么时候会产生任务的调度呢。
一:RAW-OS的任务状态改变(来自RAW-OS作者的任务管理文档):
由上图我们看到RAW-OS有这么多状态,但是我们根据状态名不难发现改变任务状态的事件:sleep(DLY)、阻塞(PEND或者PEND_TIMEOUT)、暂停(SUPEND)和resume(只要状态中有SUPEND,resume就可以让任务去掉SUPEND状态)。那我们就分析下各个事件操作
1.1 sleep
RAW_U16 raw_sleep(RAW_TICK_TYPE dly)
{
RAW_U16 error_status;
RAW_SR_ALLOC();
#if (RAW_TASK_FUNCTION_CHECK > 0)
if (raw_int_nesting) {
return RAW_NOT_CALLED_BY_ISR;
}
#endif
RAW_CRITICAL_ENTER();
if (dly) {
/*system is locked so task can not sleep just return immediately*/
SYSTEM_LOCK_PROCESS();
raw_task_active->task_state = RAW_DLY;
tick_list_insert(raw_task_active, dly);
remove_ready_list(&raw_ready_queue, raw_task_active);
}
else {
/*make current task to the end of ready list*/
move_to_ready_list_end(&raw_ready_queue, raw_task_active);
}
RAW_CRITICAL_EXIT();
raw_sched();
if (dly) {
/*task is timeout after sleep*/
error_status = block_state_post_process(raw_task_active, 0);
}
else {
error_status = RAW_SUCCESS;
}
return error_status;
}
sleep函数参数dly指task的sleep时间,单位是1个时间节拍(以下若涉及到时间都是以1个时间节拍为单位)。sleep的具体操作如下:若dly>0,将task的state改为DLY并插入到tick_list链表中(参考时间管理),接着在就绪队列中删除当前task;dly=0,将task移到就绪队列的最后面(此时task的state没改变还是RDY)。当过去dly后(tick_list_updat函数),task的state就变成RDY了并重新加入到就绪队列中。
1.2 阻塞--信号量阻塞
RAW_U16 raw_pend_object(RAW_COMMON_BLOCK_OBJECT *block_common_obj, RAW_TASK_OBJ *task_ptr, RAW_TICK_TYPE timeout)
{
/*timeout 0 should not happen here, it has been processed before*/
if (timeout == 0u) {
RAW_ASSERT(0);
}
/*task need to remember which object is blocked on*/
task_ptr->block_obj = block_common_obj;
if (timeout == RAW_WAIT_FOREVER) {
task_ptr->task_state = RAW_PEND;
}
/*task is blocked with timeout*/
else {
/*add to time sorted tick list */
tick_list_insert(task_ptr,timeout);
task_ptr->task_state = RAW_PEND_TIMEOUT;
}
/*Remove from the ready list*/
remove_ready_list(&raw_ready_queue, task_ptr);
//将task_list挂到等待信号量的链表下
if (block_common_obj->block_way == RAW_BLOCKED_WAY_FIFO) {
/*add to the end of blocked objet list*/
list_insert(&block_common_obj->block_list, &task_ptr->task_list);
}
else {
/*add to the priority sorted block list*/
add_to_priority_list(&block_common_obj->block_list, task_ptr);
}
return RAW_SUCCESS;
}
信号量阻塞事件将task从就绪队列中删除并将之添加到block_list(信号量)中。根据阻塞函数的timeout函数,分为以下两种情况:若timeout=RAW_WAIT_FOREVER,则表示task会一直等下去即state=RAW_PEND直到获取到信号量state才会变成RDY;相反state=RAW_PEND_TIMEOUT,并根据timeout将task添加到tick_list链表(等待timeout(tick_list_updat)后,task自动变成RDY状态并添加到就绪队列),但是如果在timeout之前获取到信号量,此时state也会变为RDY。
1.3 SUPEND
RAW_U16 task_suspend(RAW_TASK_OBJ *task_ptr)
{
RAW_SR_ALLOC();
RAW_CRITICAL_ENTER();
if (task_ptr == raw_task_active) {
SYSTEM_LOCK_PROCESS();
}
switch (task_ptr->task_state) {
case RAW_RDY:
task_ptr->suspend_count = 1;
task_ptr->task_state = RAW_SUSPENDED;
remove_ready_list(&raw_ready_queue, task_ptr);
break;
case RAW_DLY:
task_ptr->suspend_count = 1;
task_ptr->task_state = RAW_DLY_SUSPENDED;
break;
case RAW_PEND:
task_ptr->suspend_count = 1;
task_ptr->task_state = RAW_PEND_SUSPENDED;
break;
case RAW_PEND_TIMEOUT:
task_ptr->suspend_count = 1;
task_ptr->task_state = RAW_PEND_TIMEOUT_SUSPENDED;
break;
case RAW_SUSPENDED:
case RAW_DLY_SUSPENDED:
case RAW_PEND_SUSPENDED:
case RAW_PEND_TIMEOUT_SUSPENDED:
task_ptr->suspend_count++;
if (task_ptr->suspend_count >= 250u) {
RAW_CRITICAL_EXIT();
return RAW_SUSPENDED_COUNT_OVERFLOWED;
}
break;
default:
RAW_CRITICAL_EXIT();
return RAW_STATE_UNKNOWN;
}
RAW_CRITICAL_EXIT();
TRACE_TASK_SUSPEND(raw_task_active, task_ptr);
#if (CONFIG_RAW_SYSTEM_PREEMPTABLE > 0)
raw_sched();
return RAW_SUCCESS;
}
supend将state追加SUPEND状态,若原本state为RDY,则需要将task从就绪队列中删除并将state修改为supend。当之前的state符合时,state为SUPEND,例当state为pend_supend时获取到信号量,state就变为supend。
1.4 resume
RAW_U16 task_resume(RAW_TASK_OBJ *task_ptr)
{
RAW_SR_ALLOC();
RAW_CRITICAL_ENTER();
switch (task_ptr->task_state) {
case RAW_RDY:
case RAW_DLY:
case RAW_PEND:
case RAW_PEND_TIMEOUT:
RAW_CRITICAL_EXIT();
return HAS_NOT_SUSPENDED;
case RAW_SUSPENDED:
task_ptr->suspend_count--;
if (task_ptr->suspend_count == 0) {
/*Make task ready*/
task_ptr->task_state = RAW_RDY;
add_ready_list(&raw_ready_queue, task_ptr);//如果同当前任务的优先级相同则插到队列的最后,否则插到队列的最前面
}
break;
case RAW_DLY_SUSPENDED:
task_ptr->suspend_count--;
if (task_ptr->suspend_count == 0) {
task_ptr->task_state = RAW_DLY;
}
break;
case RAW_PEND_SUSPENDED:
task_ptr->suspend_count--;
if (task_ptr->suspend_count == 0) {
task_ptr->task_state = RAW_PEND;
}
break;
case RAW_PEND_TIMEOUT_SUSPENDED:
task_ptr->suspend_count--;
if (task_ptr->suspend_count == 0) {
task_ptr->task_state = RAW_PEND_TIMEOUT;
}
break;
default:
RAW_CRITICAL_EXIT();
return RAW_STATE_UNKNOWN;
}
RAW_CRITICAL_EXIT();
TRACE_TASK_RESUME(raw_task_active, task_ptr);
do_possible_sche();
return RAW_SUCCESS;
}
看代码可知,resume能将有supend状态的task去掉supen状态。若task只是supend状态,需要将state改为RDY并将其添加到就绪队列(若state=RDY,则RAW-OS就会task添加到就绪队列中)。
二:任务状态的改变会引起schde,下面这种情况也会sched:
void calculate_time_slice(RAW_U8 task_prio)
{
RAW_TASK_OBJ *task_ptr;
LIST *head;
RAW_SR_ALLOC();
head = &raw_ready_queue.task_ready_list[task_prio];
RAW_CRITICAL_ENTER();
/*if ready list is empty then just return because nothing is to be caculated*/
if (is_list_empty(head)) {
RAW_CRITICAL_EXIT();
return;
}
/*Always look at the first task on the ready list*/ /*because active task is the first task on the ready list*/
task_ptr = list_entry(head->next, RAW_TASK_OBJ, task_list);
/*SCHED_FIFO does not has timeslice, just return*/
if (task_ptr->sched_way == SCHED_FIFO) {
RAW_CRITICAL_EXIT(); /*FIFO 调度模式会一直执行到其他任务抢占或者是当前任务阻塞,跟task's timeslice无关*/
return;
}
/*there is only one task on this ready list, so do not need to caculate time slice*/
/*idle task must satisfy this condition*/
if (head->next->next == head) {
RAW_CRITICAL_EXIT(); /*若当前任务列表只有一个任务那自然不需要计算timeslice*/
return;
}
if (task_ptr->time_slice) {
task_ptr->time_slice--;
}
/*if current active task has time_slice, just return*/
if (task_ptr->time_slice) {
RAW_CRITICAL_EXIT();
return;
}
/*Move current active task to the end of ready list for the same priority*/
move_to_ready_list_end(&raw_ready_queue, task_ptr);
/*restore the task time slice*/
task_ptr->time_slice = task_ptr->time_total;
RAW_CRITICAL_EXIT();
}
RAW-OS会为每个任务分配time_slice(FIFO模式例外),当任务执行time_slice后,RAW-OS就会将task移到就绪队列的末端(毫无疑问此时会sched)。
Sched:
void raw_sched(void)
{
RAW_SR_ALLOC();
/*if it is in interrupt or system is locked, just return*/
if (raw_int_nesting || raw_sched_lock) {
return;
}
RAW_CPU_DISABLE();
get_ready_task(&raw_ready_queue);
/*if highest task is currently task, then no need to do switch and just return*/
if (high_ready_obj == raw_task_active) {
RAW_CPU_ENABLE();
return;
}
TRACE_TASK_SWITCH(raw_task_active, high_ready_obj);
CONTEXT_SWITCH(); //设置任务切换标志并增加timer_or_task_switch_event信号量使之响应WaitForMultipleObjects函数后停止当前任务开启最高优先级的任务
RAW_CPU_ENABLE();
}
sched函数很简单,它要做的就是执行当前优先级最高的task。那RAW-OS怎么得到最高优先级task呢,其实看RAW_RUN_QUEUE结构体就一目了然。如果当前task是最高优先级的任务,则不需要进行任务的切换(Note1);否则就要进行任务的切换了,暂停当前任务(此时state还是为RDY)执行执行最高优先级的任务(关于切换的具体机制,可以查看WaitForMultipleObjects函数)。
Note1:任务状态的改变不一定就会进行任务的调度(只有从RDY到别状态才一定会任务调度),例如在task1的状态从PEND-->RDY时,如果task1的优先级不是最高的就不进行任务切换,所以RAW-OS在这里调用do_possible_sche()(#define do_possible_sche() raw_sched())。我想RAW-OS的意思已经表达的很清楚了。
转载于:https://blog.51cto.com/pregnant/1380565