0-1write MC/OS __Basics5

2021-07-27 18:07:03 星期二

十一、任务的挂起和恢复

让OS的任务支持挂起和恢复的功能,挂起就相当于暂停,暂停后任务从就绪列表中移除,恢复即重新将任务插入就绪列表。一个任务挂起多少次就要恢复多少次才能重新运行。

1、定义任务的状态

在任务实现挂起和恢复的时候,要根据任务的状态来操作,任务的状态不同,操作也不同。

/* ---------- 任务的状态 -------*/
#define  OS_TASK_STATE_BIT_DLY               (OS_STATE)(0x01u)/*   /-------- 挂起位          */

#define  OS_TASK_STATE_BIT_PEND              (OS_STATE)(0x02u)/*   | /-----  等待位          */

#define  OS_TASK_STATE_BIT_SUSPENDED         (OS_STATE)(0x04u)/*   | | /---  延时/超时位      */

#define  OS_TASK_STATE_RDY                    (OS_STATE)(  0u)/*   0 0 0  就绪               */
#define  OS_TASK_STATE_DLY                    (OS_STATE)(  1u)/*   0 0 1  延时或者超时        */
#define  OS_TASK_STATE_PEND                   (OS_STATE)(  2u)/*   0 1 0  等待               */
#define  OS_TASK_STATE_PEND_TIMEOUT           (OS_STATE)(  3u)/*   0 1 1  等待+超时*/
#define  OS_TASK_STATE_SUSPENDED              (OS_STATE)(  4u)/*   1 0 0  挂起               */
#define  OS_TASK_STATE_DLY_SUSPENDED          (OS_STATE)(  5u)/*   1 0 1  挂起 + 延时或者超时*/
#define  OS_TASK_STATE_PEND_SUSPENDED         (OS_STATE)(  6u)/*   1 1 0  挂起 + 等待         */
#define  OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED (OS_STATE)(  7u)/*   1 1 1  挂起 + 等待 + 超时*/
#define  OS_TASK_STATE_DEL                    (OS_STATE)(255u)

2、修改任务控制块TCB

为了实现任务的挂起和恢复,需要先在任务控制块TCB中添加任务的状态TaskState和任务挂起计数器SusPendCtr两个成员。

struct os_tcb {
    CPU_STK         *StkPtr;
    CPU_STK_SIZE    StkSize;

    /* 任务延时周期个数 */
    OS_TICK         TaskDelayTicks;

    /* 任务优先级 */
    OS_PRIO         Prio;

    /* 就绪列表双向链表的下一个指针 */
    OS_TCB          *NextPtr;
    /* 就绪列表双向链表的前一个指针 */
    OS_TCB          *PrevPtr;

    /*时基列表相关字段*/
    OS_TCB          *TickNextPtr;
    OS_TCB          *TickPrevPtr;
    OS_TICK_SPOKE   *TickSpokePtr;

    OS_TICK         TickCtrMatch;
    OS_TICK         TickRemain;

    /* 时间片相关字段 */
    OS_TICK              TimeQuanta;
    OS_TICK              TimeQuantaCtr;

    OS_STATE             TaskState;/*TaskState用来表示任务的状态,在本章之前,任务出现了两种状态,一是任务刚刚创建好的时候, 处于就绪态,调用阻塞延时函数的时候处于延时态。本章要实现的是任务的挂起态,再往后的章节中还会有等待态,超时态, 删除态等。*/

#if OS_CFG_TASK_SUSPEND_EN > 0u//任务挂起功能是可选的
    /* 任务挂起函数OSTaskSuspend()计数器 */
    OS_NESTING_CTR       SuspendCtr;//(3)任务挂起计数器,任务每被挂起一次,SuspendCtr递增一次,一个任务挂起多少次就要被恢复多少次才能重新运行。
#endif

};

3、编写任务挂起和恢复函数

3.1、OSTaskSuspend()函数

CPU_CRITICAL_ENTER();

    /* 是否挂起自己 */                  
    if (p_tcb == (OS_TCB *)0) { //如果任务挂起的是自己,则判断下调度器是否锁住,如果锁住则退出返回错误码,没有锁则继续往下执行。
        p_tcb = OSTCBCurPtr;
    }

    if (p_tcb == OSTCBCurPtr) {
    /* 如果调度器锁住则不能挂起自己 */
    if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {
            CPU_CRITICAL_EXIT();
            *p_err = OS_ERR_SCHED_LOCKED;
    return;
        }
    }

    *p_err = OS_ERR_NONE;

    /* 根据任务的状态来决定挂起的动作 */
    switch (p_tcb->TaskState)
    {
        case OS_TASK_STATE_RDY:  //任务在就绪状态,则将任务的状态改为挂起态,挂起计数器置1,然后从就绪列表删除。
            OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
            p_tcb->TaskState  =  OS_TASK_STATE_SUSPENDED;
            p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
            OS_RdyListRemove(p_tcb);
            OS_CRITICAL_EXIT_NO_SCHED();
            break;

        case OS_TASK_STATE_DLY://(6)任务在延时状态,则将任务的状态改为延时加挂起态,挂起计数器置1,不用改变TCB的位置,即还是在延时的时基列表。
            p_tcb->TaskState  = OS_TASK_STATE_DLY_SUSPENDED;
            p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
            CPU_CRITICAL_EXIT();
            break;

        case OS_TASK_STATE_PEND://(7)任务在等待状态,则将任务的状态改为等待加挂起态,挂起计数器置1,不用改变TCB的位置,即还是在等待列表等待。 等待列表暂时还没有实现
            p_tcb->TaskState  = OS_TASK_STATE_PEND_SUSPENDED;
            p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
            CPU_CRITICAL_EXIT();
            break;

        case OS_TASK_STATE_PEND_TIMEOUT://(8)任务在等待加超时态, 则将任务的状态改为等待加超时加挂起态,挂起计数器置1,不用改变TCB的位置,即还在等待和时基这两个列表中。
            p_tcb->TaskState  = OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED;
            p_tcb->SuspendCtr = (OS_NESTING_CTR)1;
            CPU_CRITICAL_EXIT();
            break;

        case OS_TASK_STATE_SUSPENDED://(9)只要有一个是挂起状态,则将挂起计数器加一操作,不用改变TCB的位置。
        case OS_TASK_STATE_DLY_SUSPENDED:
        case OS_TASK_STATE_PEND_SUSPENDED:
        case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
            p_tcb->SuspendCtr++;
            CPU_CRITICAL_EXIT();
            break;

        default://(10)其他状态则无效,退出返回状态无效错误码。
            CPU_CRITICAL_EXIT();
            *p_err = OS_ERR_STATE_INVALID;
            return;
    }

    /* 任务切换 */
    OSSched();//(11)任务切换。凡是涉及改变任务状态的地方,都需要进行任务切换。
}

3.2、OSTaskResume()函数

OSTaskResume()函数用于恢复被挂起的函数,但是不能恢复自己,挂起倒是可以挂起自己

 *p_err  = OS_ERR_NONE;
/* 根据任务的状态来决定挂起的动作 */
switch (p_tcb->TaskState) {//(3)根据任务的状态来决定恢复操作。
case OS_TASK_STATE_RDY://(4)只要任务没有被挂起,则退出返回任务没有被挂起的错误码。
case OS_TASK_STATE_DLY:
case OS_TASK_STATE_PEND:
case OS_TASK_STATE_PEND_TIMEOUT:
        CPU_CRITICAL_EXIT();
        *p_err = OS_ERR_TASK_NOT_SUSPENDED;
break;

case OS_TASK_STATE_SUSPENDED://(5)任务只在挂起态, 则递减挂起计数器SuspendCtr,如果SuspendCtr等于0,则将任务的状态改为就绪态,并让任务就绪。
        OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
        p_tcb->SuspendCtr--;
if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
            p_tcb->TaskState = OS_TASK_STATE_RDY;
            OS_TaskRdy(p_tcb);
        }
        OS_CRITICAL_EXIT_NO_SCHED();
break;

case OS_TASK_STATE_DLY_SUSPENDED://(6)任务在延时加挂起态, 则递减挂起计数器SuspendCtr,如果SuspendCtr等于0,则将任务的状态改为延时态。
        p_tcb->SuspendCtr--;
if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
            p_tcb->TaskState = OS_TASK_STATE_DLY;
        }
        CPU_CRITICAL_EXIT();
break;

case OS_TASK_STATE_PEND_SUSPENDED://(7)任务在延时加等待态, 则递减挂起计数器SuspendCtr,如果SuspendCtr等于0,则将任务的状态改为等待态。
        p_tcb->SuspendCtr--;
if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
            p_tcb->TaskState = OS_TASK_STATE_PEND;
        }
        CPU_CRITICAL_EXIT();
break;

case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED://(8)任务在等待加超时加挂起态, 则递减挂起计数器SuspendCtr,如果SuspendCtr等于0,则将任务的状态改为等待加超时态
        p_tcb->SuspendCtr--;
if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) {
            p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT;
        }
        CPU_CRITICAL_EXIT();
break;

default://(9)其他状态则无效,退出返回状态无效错误码。
        CPU_CRITICAL_EXIT();
        *p_err = OS_ERR_STATE_INVALID;
return;
    }

/* 任务切换 */
    OSSched();//(10)任务切换。凡是涉及改变任务状态的地方,都需要进行任务切换。
}

十二、任务的删除

OS的任务支持删除操作,一个任务被删除后就进入休眠态,要想继续运行必须创新创建。

1、编写任务删除函数实现任务删除

OSTaskDel()函数

任务删除函数OSTaskDel()用于删除一个指定的任务,也可以删除自身

#if OS_CFG_TASK_DEL_EN > 0u//(1)任务删除是一个可选功能
void  OSTaskDel (OS_TCB  *p_tcb,
                OS_ERR  *p_err)
{
    CPU_SR_ALLOC();

    /* 不允许删除空闲任务 系统必须至少有一个任务在运行,当没有其他用户任务运行的时候,系统就会运行空闲任务。*/
    if (p_tcb == &OSIdleTaskTCB)
    {
        *p_err = OS_ERR_TASK_DEL_IDLE;
         return;
    }

    /* 删除自己 */
    if (p_tcb == (OS_TCB *)0) //(3)删除自己。
    {
        CPU_CRITICAL_ENTER();
        p_tcb  = OSTCBCurPtr;
        CPU_CRITICAL_EXIT();
    }

    OS_CRITICAL_ENTER();

    /* 根据任务的状态来决定删除的动作 */
    switch (p_tcb->TaskState)
    {
        case OS_TASK_STATE_RDY://(4)任务只在就绪态,则从就绪列表移除。
        OS_RdyListRemove(p_tcb);
        break;

        case OS_TASK_STATE_SUSPENDED://(5)任务只是被挂起,则退出返回,不用做什么。
        break;

        /* 任务只是在延时,并没有在任何等待列表*/
        case OS_TASK_STATE_DLY://(6)任务在延时或者是延时加挂起,则从时基列表移除。
        case OS_TASK_STATE_DLY_SUSPENDED:
                OS_TickListRemove(p_tcb);
        break;

        case OS_TASK_STATE_PEND://(7)任务在多种状态,但只要有一种是等待状态,就需要从等待列表移除。如果任务等待是任务自身的信号量和消息, 则直接退出返回,因为任务信号量和消息是没
        case OS_TASK_STATE_PEND_SUSPENDED://有等待列表的。
        case OS_TASK_STATE_PEND_TIMEOUT:
        case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
                OS_TickListRemove(p_tcb);

#if 0/* 目前我们还没有实现等待列表,暂时先把这部分代码注释 */
    /* 看看在等待什么 */
    switch (p_tcb->PendOn) {
        case OS_TASK_PEND_ON_NOTHING:
        /* 任务信号量和队列没有等待队列,直接退出 */
        case OS_TASK_PEND_ON_TASK_Q:
        case OS_TASK_PEND_ON_TASK_SEM:
        break;

        /* 从等待列表移除 */
        case OS_TASK_PEND_ON_FLAG:
        case OS_TASK_PEND_ON_MULTI:
        case OS_TASK_PEND_ON_MUTEX:
        case OS_TASK_PEND_ON_Q:
        case OS_TASK_PEND_ON_SEM:
                    OS_PendListRemove(p_tcb);
        break;

        default:
        break;
                }
        break;
        #endif
        default:
                OS_CRITICAL_EXIT();
                *p_err = OS_ERR_STATE_INVALID;
        return;
    }

    /* 初始化TCB为默认值 */
    OS_TaskInitTCB(p_tcb);//(8)
    /* 修改任务的状态为删除态,即处于休眠 */
    p_tcb->TaskState = (OS_STATE)OS_TASK_STATE_DEL;//(9)

    OS_CRITICAL_EXIT_NO_SCHED();
    /* 任务切换,寻找最高优先级的任务 */
    OSSched();//(10)

    *p_err = OS_ERR_NONE;
}
#endif/* OS_CFG_TASK_DEL_EN > 0u */
posted @ 2021-11-30 20:31  cswft  Views(40)  Comments(0Edit  收藏  举报