UCOSIII中延迟Post的理解

序言

今天我们一起来看看延迟Post的具体实现机制,我会按照我的学习过程来介绍。

打开OS_IntQPost

函数参数的理解,可以看源码注释,说得很清楚了,我这里主要介绍一些我的疑惑

void  OS_IntQPost (OS_OBJ_TYPE   type,
                   void         *p_obj,
                   void         *p_void,
                   OS_MSG_SIZE   msg_size,
                   OS_FLAGS      flags,
                   OS_OPT        opt,
                   CPU_TS        ts,
                   OS_ERR       *p_err)
{
    CPU_SR_ALLOC();



#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

    CPU_CRITICAL_ENTER();
    if (OSIntQNbrEntries < OSCfg_IntQSize) {                /* Make sure we haven't already filled the ISR queue      */
        OSIntQNbrEntries++;

        if (OSIntQNbrEntriesMax < OSIntQNbrEntries) {
            OSIntQNbrEntriesMax = OSIntQNbrEntries;
        }

        OSIntQInPtr->Type       = type;                     /* Save object type being posted                          */
        OSIntQInPtr->ObjPtr     = p_obj;                    /* Save pointer to object being posted                    */
        OSIntQInPtr->MsgPtr     = p_void;                   /* Save pointer to message if posting to a message queue  */
        OSIntQInPtr->MsgSize    = msg_size;                 /* Save the message size   if posting to a message queue  */
        OSIntQInPtr->Flags      = flags;                    /* Save the flags if posting to an event flag group       */
        OSIntQInPtr->Opt        = opt;                      /* Save post options                                      */
        OSIntQInPtr->TS         = ts;                       /* Save time stamp                                        */

        OSIntQInPtr             =  OSIntQInPtr->NextPtr;    /* Point to the next interrupt handler queue entry        */

        OSRdyList[0].NbrEntries = (OS_OBJ_QTY)1;            /* Make the interrupt handler task ready to run           */
        OSRdyList[0].HeadPtr    = &OSIntQTaskTCB;
        OSRdyList[0].TailPtr    = &OSIntQTaskTCB;
        OS_PrioInsert(0u);                                  /* Add task priority 0 in the priority table              */
        if (OSPrioCur != 0) {                               /* Chk if OSIntQTask is not running                       */
            OSPrioSaved         = OSPrioCur;                /* Save current priority                                  */
        }

       *p_err                   = OS_ERR_NONE;
    } else {
        OSIntQOvfCtr++;                                     /* Count the number of ISR queue overflows                */
       *p_err                   = OS_ERR_INT_Q_FULL;
    }
    CPU_CRITICAL_EXIT();
}

我之前对延迟Post机制的理解是:通过将Post信号这件事情保存在一个队列中,然后由一个OSIntQTask任务来处理这个队列,将队列中的信息重新Post给对应的对象。事实的确如此,只不过我之前的理解过于概念化。下面我将会就代码进行介绍。

我们看上面的代码会发现由很多不懂的地方,比如OSIntQNbrEntries、OSCfg_IntQSize、OSIntQInPtr这三个是什么东西呢,我使用全局查找发现了这样一条代码

OSIntQInPtr         = p_int_q_next;

这条代码是来自下面这个函数中

void  OS_IntQTaskInit (OS_ERR  *p_err)
{
    OS_INT_Q      *p_int_q;
    OS_INT_Q      *p_int_q_next;
    OS_OBJ_QTY     i;



#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

    OSIntQOvfCtr = (OS_QTY)0u;                              /* Clear the ISR queue overflow counter                   */

    if (OSCfg_IntQBasePtr == (OS_INT_Q *)0) {
       *p_err = OS_ERR_INT_Q;
        return;
    }

    if (OSCfg_IntQSize < (OS_OBJ_QTY)2u) {
       *p_err = OS_ERR_INT_Q_SIZE;
        return;
    }

    OSIntQTaskTimeMax = (CPU_TS)0;

    p_int_q           = OSCfg_IntQBasePtr;                  /* Initialize the circular ISR queue                      */
    p_int_q_next      = p_int_q;
    p_int_q_next++;
    for (i = 0u; i < OSCfg_IntQSize; i++) {
        p_int_q->Type    =  OS_OBJ_TYPE_NONE;
        p_int_q->ObjPtr  = (void      *)0;
        p_int_q->MsgPtr  = (void      *)0;
        p_int_q->MsgSize = (OS_MSG_SIZE)0u;
        p_int_q->Flags   = (OS_FLAGS   )0u;
        p_int_q->Opt     = (OS_OPT     )0u;
        p_int_q->NextPtr = p_int_q_next;
        p_int_q++;
        p_int_q_next++;
    }
    p_int_q--;
    p_int_q_next        = OSCfg_IntQBasePtr;
    p_int_q->NextPtr    = p_int_q_next;
    OSIntQInPtr         = p_int_q_next;
    OSIntQOutPtr        = p_int_q_next;
    OSIntQNbrEntries    = (OS_OBJ_QTY)0u;
    OSIntQNbrEntriesMax = (OS_OBJ_QTY)0u;

                                                            /* -------------- CREATE THE ISR QUEUE TASK ------------- */
    if (OSCfg_IntQTaskStkBasePtr == (CPU_STK *)0) {
       *p_err = OS_ERR_INT_Q_STK_INVALID;
        return;
    }

    if (OSCfg_IntQTaskStkSize < OSCfg_StkSizeMin) {
       *p_err = OS_ERR_INT_Q_STK_SIZE_INVALID;
        return;
    }

    OSTaskCreate((OS_TCB     *)&OSIntQTaskTCB,
                 (CPU_CHAR   *)((void *)"uC/OS-III ISR Queue Task"),
                 (OS_TASK_PTR )OS_IntQTask,
                 (void       *)0,
                 (OS_PRIO     )0u,                          /* This task is ALWAYS at priority '0' (i.e. highest)     */
                 (CPU_STK    *)OSCfg_IntQTaskStkBasePtr,
                 (CPU_STK_SIZE)OSCfg_IntQTaskStkLimit,
                 (CPU_STK_SIZE)OSCfg_IntQTaskStkSize,
                 (OS_MSG_QTY  )0u,
                 (OS_TICK     )0u,
                 (void       *)0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR     *)p_err);
}

我们我们继续阅读这个函数,不久就又会发现不认识的东西OSCfg_IntQBasePtr,我们继续去看看它的定义

OS_INT_Q     * const  OSCfg_IntQBasePtr          = (OS_INT_Q   *)&OSCfg_IntQ[0];

到这里,我们发现了一个数组OSCfg_IntQ,这个数组长什么样呢,我们继续往下看

OS_INT_Q       OSCfg_IntQ          [OS_CFG_INT_Q_SIZE];

这是一个包含OS_CFG_INT_Q_SIZE个OS_INT_Q的数组,那么OS_INT_Q长什么样呢,我们来看看

struct  os_int_q {
    OS_OBJ_TYPE          Type;                              /* Type of object placed in the circular list             */
    OS_INT_Q            *NextPtr;                           /* Pointer to next OS_INT_Q in  circular list             */
    void                *ObjPtr;                            /* Pointer to object placed in the queue                  */
    void                *MsgPtr;                            /* Pointer to message if posting to a message queue       */
    OS_MSG_SIZE          MsgSize;                           /* Message Size       if posting to a message queue       */
    OS_FLAGS             Flags;                             /* Value of flags if posting to an event flag group       */
    OS_OPT               Opt;                               /* Post Options                                           */
    CPU_TS               TS;                                /* Timestamp                                              */
};

就长这个样子,它是用来保存一个Post过程的(向谁Post,Post什么,Post多少,等等)。我们分析到这里就是得到了一个数组,我们调用OS_IntQTaskInit对这个数组进行初始化,并初始化OSIntQXXX这些参数,让它们与这个数组联系起来,之后我们就可以使用OSIntQXXX这些参数了,现在回到OS_IntQPost

void  OS_IntQPost (OS_OBJ_TYPE   type,
                   void         *p_obj,
                   void         *p_void,
                   OS_MSG_SIZE   msg_size,
                   OS_FLAGS      flags,
                   OS_OPT        opt,
                   CPU_TS        ts,
                   OS_ERR       *p_err)
{
    CPU_SR_ALLOC();



#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

    CPU_CRITICAL_ENTER();
    if (OSIntQNbrEntries < OSCfg_IntQSize) {                /* Make sure we haven't already filled the ISR queue      */
        OSIntQNbrEntries++;

        if (OSIntQNbrEntriesMax < OSIntQNbrEntries) {
            OSIntQNbrEntriesMax = OSIntQNbrEntries;
        }

        OSIntQInPtr->Type       = type;                     /* Save object type being posted                          */
        OSIntQInPtr->ObjPtr     = p_obj;                    /* Save pointer to object being posted                    */
        OSIntQInPtr->MsgPtr     = p_void;                   /* Save pointer to message if posting to a message queue  */
        OSIntQInPtr->MsgSize    = msg_size;                 /* Save the message size   if posting to a message queue  */
        OSIntQInPtr->Flags      = flags;                    /* Save the flags if posting to an event flag group       */
        OSIntQInPtr->Opt        = opt;                      /* Save post options                                      */
        OSIntQInPtr->TS         = ts;                       /* Save time stamp                                        */

        OSIntQInPtr             =  OSIntQInPtr->NextPtr;    /* Point to the next interrupt handler queue entry        */

        OSRdyList[0].NbrEntries = (OS_OBJ_QTY)1;            /* Make the interrupt handler task ready to run           */
        OSRdyList[0].HeadPtr    = &OSIntQTaskTCB;
        OSRdyList[0].TailPtr    = &OSIntQTaskTCB;
        OS_PrioInsert(0u);                                  /* Add task priority 0 in the priority table              */
        if (OSPrioCur != 0) {                               /* Chk if OSIntQTask is not running                       */
            OSPrioSaved         = OSPrioCur;                /* Save current priority                                  */
        }

       *p_err                   = OS_ERR_NONE;
    } else {
        OSIntQOvfCtr++;                                     /* Count the number of ISR queue overflows                */
       *p_err                   = OS_ERR_INT_Q_FULL;
    }
    CPU_CRITICAL_EXIT();
}

现在再看应该没什么问题了,我们把一个Post过程以一个数组元素内容的形式填充某个数组元素,然后让OS_IntQTask就绪,准备处理OSIntQ,接下来我们要探究一下这个处理任务,看看它是如何处理这个队列的

OS_IntQTask

这是一个系统任务,是五个系统任务中第一个被初始化的,

void  OS_IntQTask (void  *p_arg)
{
    CPU_BOOLEAN  done;
    CPU_TS       ts_start;
    CPU_TS       ts_end;
    CPU_SR_ALLOC();



    p_arg = p_arg;                                          /* Not using 'p_arg', prevent compiler warning            */
    while (DEF_ON) {
        done = DEF_FALSE;
        while (done == DEF_FALSE) {
            CPU_CRITICAL_ENTER();
            if (OSIntQNbrEntries == (OS_OBJ_QTY)0u) {
                OSRdyList[0].NbrEntries = (OS_OBJ_QTY)0u;   /* Remove from ready list                                 */
                OSRdyList[0].HeadPtr    = (OS_TCB   *)0;
                OSRdyList[0].TailPtr    = (OS_TCB   *)0;
                OS_PrioRemove(0u);                          /* Remove from the priority table                         */
                CPU_CRITICAL_EXIT();
                OSSched();
                done = DEF_TRUE;                            /* No more entries in the queue, we are done              */
            } else {
                CPU_CRITICAL_EXIT();
                ts_start = OS_TS_GET();
                OS_IntQRePost();
                ts_end   = OS_TS_GET() - ts_start;          /* Measure execution time of tick task                    */
                if (OSIntQTaskTimeMax < ts_end) {
                    OSIntQTaskTimeMax = ts_end;
                }
                CPU_CRITICAL_ENTER();
                OSIntQOutPtr = OSIntQOutPtr->NextPtr;       /* Point to next item in the ISR queue                    */
                OSIntQNbrEntries--;
                CPU_CRITICAL_EXIT();
            }
        }
    }
}

具体过程自己看一下吧,这里用到了一个OS_IntQRePost(),里面的内容就是调用普通的Post,剩下的一些细节,自己看看吧,我不看了,反正一看就懂,懂了也记不住,哈哈哈哈。

总结

OS_IntQPost将Post过程信息保存在数组OSCfg_IntQ,然后使OS_IntQTask就绪,去处理这个数组(也就是重新Post里面的内容)。


Stay studying

See you next time

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值