认识uCOS-II(二)

3、事件管理及等待任务表

ucosii中的任务间的同步和通信主要通过事件OS_EVENT来管理的,结构体OS_EVENT定义如下:

typedef struct os_event {
    INT8U    OSEventType;                 
    void    *OSEventPtr;                     
    INT16U   OSEventCnt;                     
#if OS_LOWEST_PRIO <= 63
    INT8U    OSEventGrp;                   
    INT8U    OSEventTbl[OS_EVENT_TBL_SIZE];  
#else
    INT16U   OSEventGrp;                     
    INT16U   OSEventTbl[OS_EVENT_TBL_SIZE];  
#endif
} OS_EVENT;

成员变量OSEventType主要由信号量、互斥信号量、消息邮箱和消息队列几种类型。类似于任务优先级就绪表,OSEventGrp和OSEventTbl是用来管理等待该事件的任务等待表。若事件有效(为非0),则任务可直接申请该事件,若事件无效(为0),则任务需要在事件等待表中置位(以任务优先级号来标注其在事件等待表中的位置)。

(1)、信号量

一个刚创建且计数器值为10的信号量示意图如下:
semaphore
上图中看出,刚初始化的信号量,其任务等待表中均为0。下面介绍在信号量创建、请求、发送、删除和查询信号量中用到的几个内核函数。
a、初始化任务事件等待表

void  OS_EventWaitListInit (OS_EVENT *pevent)
{
#if OS_LOWEST_PRIO <= 63
    INT8U  *ptbl;
#else
    INT16U *ptbl;
#endif
    INT8U   i;

 /* No task waiting on event */
    pevent->OSEventGrp = 0;                     
    ptbl               = &pevent->OSEventTbl[0];

    for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
        *ptbl++ = 0;
    }
}

b、让任务由就绪状态转换为等待状态,等待时间由成员变量OSTCBCur->OSTCBDly = timeout; 决定,并由系统滴答函数OSTimeTick对等待时间递减操作,系统在请求信号量等待期间也进行任务调度。等待超时后,任务由等待状态变为就绪状态。

void  OS_EventTaskWait (OS_EVENT *pevent)
{
    INT8U  y;

    OSTCBCur->OSTCBEventPtr = pevent;                 
      /* Put task in waiting list */
    pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;    
    pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;

     /* Task no longer ready  */
    y =  OSTCBCur->OSTCBY;            
    OSRdyTbl[y]  &= ~OSTCBCur->OSTCBBitX;
    if (OSRdyTbl[y] == 0) {
        OSRdyGrp &= ~OSTCBCur->OSTCBBitY;        
    }
}

c、删除任务的等待状态

void  OS_EventTaskRemove (OS_TCB   *ptcb,
                          OS_EVENT *pevent)
{
    INT8U  y;

/* Remove task from wait list */
    y  =  ptcb->OSTCBY;
    pevent->OSEventTbl[y]  &= ~ptcb->OSTCBBitX;         
    if (pevent->OSEventTbl[y] == 0) {
        pevent->OSEventGrp &= ~ptcb->OSTCBBitY;
    }
}

d、SYSTEM TICK处理,遍历整个任务链表,进行时间处理

void  OSTimeTick (void)
{
    OS_TCB    *ptcb;

        ptcb = OSTCBList;                                  /* Point at first TCB in TCB list */
        while (ptcb->OSTCBPrio != OS_TASK_IDLE_PRIO) {     
            OS_ENTER_CRITICAL();
            if (ptcb->OSTCBDly != 0) {                     
                if (--ptcb->OSTCBDly == 0) {               
                    if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {
ptcb->OSTCBStat  &= ~(INT8U)OS_STAT_PEND_ANY;         
  ptcb->OSTCBStatPend = OS_STAT_PEND_TO;                 
   } else {
   ptcb->OSTCBStatPend = OS_STAT_PEND_OK;
   }
if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) {  
 OSRdyGrp               |= ptcb->OSTCBBitY;         
   OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
                    }
                }
            }
            ptcb = ptcb->OSTCBNext;                        
            OS_EXIT_CRITICAL();
        }
    }
}

e、任务由等待状态设置为就绪状态

INT8U  OS_EventTaskRdy (OS_EVENT *pevent, void *pmsg, INT8U msk, INT8U pend_stat)
{
    OS_TCB  *ptcb;
    INT8U    y;
    INT8U    x;
    INT8U    prio;

    y    = OSUnMapTbl[pevent->OSEventGrp];              /* Find HPT waiting for message                */
    x    = OSUnMapTbl[pevent->OSEventTbl[y]];
    prio = (INT8U)((y << 3) + x);                       

    ptcb  =  OSTCBPrioTbl[prio];        
    ptcb->OSTCBDly        =  0;                         
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
    ptcb->OSTCBMsg        =  pmsg;                      
#else
    pmsg                  =  pmsg;                      
#endif
    ptcb->OSTCBStat      &= ~msk;                       
    ptcb->OSTCBStatPend   =  pend_stat;                 

    if ((ptcb->OSTCBStat &   OS_STAT_SUSPEND) == OS_STAT_RDY) {
        OSRdyGrp         |=  ptcb->OSTCBBitY;           
        OSRdyTbl[y]      |=  ptcb->OSTCBBitX;
    }

    OS_EventTaskRemove(ptcb, pevent);                   
    return (prio);
}

信号量semaphore的相关操作函数见os_sem.c

(2)消息邮箱和消息队列

任务间的通信主要是通过消息邮箱和消息队列来实现的,消息队列用到一个新的结构体OS_Q,其定义如下:

typedef struct os_q {                  
    struct os_q   *OSQPtr;              
    void         **OSQStart;           
    void         **OSQEnd;              
    void         **OSQIn;               
    void         **OSQOut;              
    INT16U         OSQSize;             
    INT16U         OSQEntries;         
} OS_Q;

os_q structure
使用消息队列需先定义指针数组void *MessageStorage[size] 。邮箱和队列具体函数实现同信号量类似。

(3)信号量集

信号量集的主要功能是实现多个信号量的组合,其各个信号量均为二值信号量。定义的信号量集和等待任务链表结构体如下:

OS_FLAG_GRP       OSFlagTbl[OS_MAX_FLAGS];  
OS_FLAG_GRP      *OSFlagFreeList;

typedef struct os_flag_grp {                
    INT8U         OSFlagType;               
    void         *OSFlagWaitList;           
    OS_FLAGS      OSFlagFlags;              
} OS_FLAG_GRP;


typedef struct os_flag_node {               
    void         *OSFlagNodeNext;           
    void         *OSFlagNodePrev;           
    void         *OSFlagNodeTCB;            
    void         *OSFlagNodeFlagGrp;        
    OS_FLAGS      OSFlagNodeFlags;          
    INT8U         OSFlagNodeWaitType;      

} OS_FLAG_NODE;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值