uC/OS-II操作系统分析 (三)

本文详细分析了uC/OS-II操作系统中的信号量查询OSSemQuery()、邮箱创建OSMboxCreate()、邮箱接收OSMboxPend()、发送OSMboxPost()以及消息队列的相关函数,包括创建、接收、发送和查询等操作。同时,介绍了就绪表的管理,包括就绪表示意图、查询方法及去除优先级的逻辑。

 

 

 

1.1.1 OSSemQuery() 信号量查询

源码分析

INT8U OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *pdata)

 

  1. OS_EVENT *pevent 要查询的信号量 ECB 指针

  2. OS_SEM_DATA * pdata 用于存储查询信号量副本的指针 ,下面是 OS_SEM_DATA 的具体实现,它用于存储 ECB 的三个内容,计数值,等待列表信息,可以说是一个简易的 ECB 。在调用之前仍然需要先建立一个全局的 OS_SEM_DATA 来存储。直接使用 pdata 可以进行相关信息的操作。

#if OS_SEM_EN > 0

typedef struct {

INT16U OSCnt; /* Semaphore count */

INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */

INT8U OSEventGrp; /* Group corresponding to tasks waiting for event to occur */

} OS_SEM_DATA;

#endif

 

 

#if OS_SEM_QUERY_EN > 0

INT8U OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *pdata)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

INT8U *psrc;

INT8U *pdest;

 

 

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) { /* 查看 ECB 是否有效 */

return (OS_ERR_PEVENT_NULL);

}

if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* 查看 ECB 类型 */

return (OS_ERR_EVENT_TYPE);

}

#endif

OS_ENTER_CRITICAL();

pdata->OSEventGrp = pevent->OSEventGrp; /* 复制等待列表组信息 */

psrc = &pevent->OSEventTbl[0];

pdest = &pdata->OSEventTbl[0];

///////******** 这种定义是否更高效,源码用 for 循环有什么区别?

#if OS_EVENT_TBL_SIZE > 0

*pdest++ = *psrc++;

#endif

 

#if OS_EVENT_TBL_SIZE > 1

*pdest++ = *psrc++;

#endif

 

#if OS_EVENT_TBL_SIZE > 2

*pdest++ = *psrc++;

#endif

 

#if OS_EVENT_TBL_SIZE > 3

*pdest++ = *psrc++;

#endif

 

#if OS_EVENT_TBL_SIZE > 4

*pdest++ = *psrc++;

#endif

 

#if OS_EVENT_TBL_SIZE > 5

*pdest++ = *psrc++;

#endif

 

#if OS_EVENT_TBL_SIZE > 6

*pdest++ = *psrc++;

#endif

 

#if OS_EVENT_TBL_SIZE > 7

*pdest = *psrc;

#endif

pdata->OSCnt = pevent->OSEventCnt; /* 获得信号量计数值 */

OS_EXIT_CRITICAL();

return (OS_NO_ERR);

}

#endif /* OS_SEM_QUERY_EN */

 

1.2邮箱

1.2.1 OSMboxCreate() 邮箱信号量创建

OS_EVENT *OSMboxCreate (void *msg)

 

  1. Void *msg 携带的信息

说明:

  1. OSMboxCreate 所携带的变量是 void *msg , 而 OSSemCreate 携带的是 INT16U cnt ,邮箱没有 OSEventCnt 变量,都置为 0 ,但要 OSEventPtr 指向 msg

  2. 邮箱一旦建立,是不能被删除的

OS_EVENT *OSMboxCreate (void *msg)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

OS_EVENT *pevent;

 

 

if (OSIntNesting > 0) { /* See if called from ISR ... */

return ((OS_EVENT *)0); /* ... can't CREATE from an ISR */

}

OS_ENTER_CRITICAL();

pevent = OSEventFreeList; /* Get next free event control block */

if (OSEventFreeList != (OS_EVENT *)0) { /* See if pool of free ECB pool was empty */

OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;

}

OS_EXIT_CRITICAL();

if (pevent != (OS_EVENT *)0) {

pevent->OSEventType = OS_EVENT_TYPE_MBOX;

pevent->OSEventCnt = 0;

pevent->OSEventPtr = msg; /* Deposit message in event control block */

OS_EventWaitListInit(pevent);

}

return (pevent); /* Return pointer to event control block */

}

 

1.2.2 OSMboxPend () 等待一个邮箱中的信息

void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)

 

void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

void *msg;

 

if (OSIntNesting > 0) { /* See if called from ISR ... */

*err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */

return ((void *)0);

}

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */

*err = OS_ERR_PEVENT_NULL;

return ((void *)0);

}

if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */

*err = OS_ERR_EVENT_TYPE;

return ((void *)0);

}

#endif

OS_ENTER_CRITICAL();

msg = pevent->OSEventPtr;

if (msg != (void *)0) { /* See if there is already a message */

pevent->OSEventPtr = (void *)0; /* Clear the mailbox */

OS_EXIT_CRITICAL();

*err = OS_NO_ERR;

return (msg); /* Return the message received (or NULL) */

}

OSTCBCur->OSTCBStat |= OS_STAT_MBOX; /* Message not available, task will pend */

OSTCBCur->OSTCBDly = timeout; /* Load timeout in TCB */

OS_EventTaskWait(pevent); /* Suspend task until event or timeout ccurs */

OS_EXIT_CRITICAL();

OS_Sched(); /* Find next highest priority task ready to run */

OS_ENTER_CRITICAL();

msg = OSTCBCur->OSTCBMsg;

if (msg != (void *)0) { /* See if we were given the message */

OSTCBCur->OSTCBMsg = (void *)0; /* Yes, clear message received */

OSTCBCur->OSTCBStat = OS_STAT_RDY;

OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* No longer waiting for event */

OS_EXIT_CRITICAL();

*err = OS_NO_ERR;

return (msg); /* Return the message received */

}

OS_EventTO(pevent); /* Timed out, Make task ready */

OS_EXIT_CRITICAL();

*err = OS_TIMEOUT; /* Indicate that a timeout occured */

return ((void *)0); /* Return a NULL message */

}

 

1.2.3 OSMboxPost() 发送一个信息到邮箱

INT8U OSMboxPost (OS_EVENT *pevent, void *msg)

 

#if OS_MBOX_POST_EN > 0

INT8U OSMboxPost (OS_EVENT *pevent, void *msg)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

 

 

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */

return (OS_ERR_PEVENT_NULL);

}

if (msg == (void *)0) { /* Make sure we are not posting a NULL pointer */

return (OS_ERR_POST_NULL_PTR);

}

if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */

return (OS_ERR_EVENT_TYPE);

}

#endif

OS_ENTER_CRITICAL();

if (pevent->OSEventGrp != 0x00) { /* See if any task pending on mailbox */

OS_EventTaskRdy(pevent, msg, OS_STAT_MBOX);

/* Ready highest priority task waiting on event */

OS_EXIT_CRITICAL();

OS_Sched(); /* Find highest priority task ready to run */

return (OS_NO_ERR);

}

if (pevent->OSEventPtr != (void *)0) { /* Make sure mailbox doesn't already have a msg */

OS_EXIT_CRITICAL();

return (OS_MBOX_FULL);

}

pevent->OSEventPtr = msg; /* Place message in mailbox */

OS_EXIT_CRITICAL();

return (OS_NO_ERR);

}

#endif

 

1.2.4 OSMboxAccept()无等待的从邮箱得到一个信息

 

#if OS_MBOX_ACCEPT_EN > 0

void *OSMboxAccept (OS_EVENT *pevent)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

void *msg;

 

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */

return ((void *)0);

}

if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */

return ((void *)0);

}

#endif

OS_ENTER_CRITICAL();

msg = pevent->OSEventPtr;

pevent->OSEventPtr = (void *)0; /* Clear the mailbox */

OS_EXIT_CRITICAL();

return (msg); /* Return the message received (or NULL) */

}

#endif

 

1.2.5 OSMailQuary() 查询邮箱实验

 

#if OS_MBOX_QUERY_EN > 0

INT8U OSMboxQuery (OS_EVENT *pevent, OS_MBOX_DATA *pdata)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

INT8U *psrc;

INT8U *pdest;

 

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */

return (OS_ERR_PEVENT_NULL);

}

if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */

return (OS_ERR_EVENT_TYPE);

}

#endif

OS_ENTER_CRITICAL();

pdata->OSEventGrp = pevent->OSEventGrp; /* Copy message mailbox wait list */

psrc = &pevent->OSEventTbl[0];

pdest = &pdata->OSEventTbl[0];

 

#if OS_EVENT_TBL_SIZE > 0

*pdest++ = *psrc++;

#endif

 

#if OS_EVENT_TBL_SIZE > 1

*pdest++ = *psrc++;

#endif

 

#if OS_EVENT_TBL_SIZE > 2

*pdest++ = *psrc++;

#endif

 

#if OS_EVENT_TBL_SIZE > 3

*pdest++ = *psrc++;

#endif

 

#if OS_EVENT_TBL_SIZE > 4

*pdest++ = *psrc++;

#endif

 

#if OS_EVENT_TBL_SIZE > 5

*pdest++ = *psrc++;

#endif

 

#if OS_EVENT_TBL_SIZE > 6

*pdest++ = *psrc++;

#endif

 

#if OS_EVENT_TBL_SIZE > 7

*pdest = *psrc;

#endif

pdata->OSMsg = pevent->OSEventPtr; /* Get message from mailbox */

OS_EXIT_CRITICAL();

return (OS_NO_ERR);

}

#endif /* OS_MBOX_QUERY_EN */

 

1.3消息队列

 

typedef struct os_q { /* 队列控制块 */

struct os_q *OSQPtr; /* 指向队列控制块中的下一个块 */

void **OSQStart; /* 指向消息队列的指针数组的起始地址的指针 */

void **OSQEnd; /* 指向消息队列结束单元的下一个地址的指针 */

void **OSQIn; /* 指向消息队列中插入下一条消息的位置的指针 */

void **OSQOut; /* 指向消息队列中下一个取出消息的位置的指针 */

INT16U OSQSize; /* 是消息队列中总的单元数,最大 65535 */

INT16U OSQEntries; /* 当前队列入口点 ,是消息队列中当前的消息数量 */

} OS_Q;

 

1.3.1 OSQCreate() 建立一个消息队列

 

OS_EVENT *OSQCreate (void **start, INT16U size)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

OS_EVENT *pevent;

OS_Q *pq;

 

 

if (OSIntNesting > 0) { /* 看是否从中断服务程序中执行函数 */

return ((OS_EVENT *)0); /* 返回空 */

}

OS_ENTER_CRITICAL();

pevent = OSEventFreeList; /* 从空闲列表中获得 ECB */

if (OSEventFreeList != (OS_EVENT *)0) { /* 看是否到了事件空闲列表的尾端 */

OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; /* ECB 指向下一个空闲 */

}

OS_EXIT_CRITICAL();

if (pevent != (OS_EVENT *)0) { /* 看是否得到 ECB */

OS_ENTER_CRITICAL();

pq = OSQFreeList; /* 得到一个空闲队列控制块 */

if (pq != (OS_Q *)0) { /* 该队列控制块可用? */

OSQFreeList = OSQFreeList->OSQPtr; /* 是则调整空闲队列控制块指针 */

OS_EXIT_CRITICAL();

pq->OSQStart = start; /* 初始化队列信息 */

pq->OSQEnd = &start[size];

pq->OSQIn = start;

pq->OSQOut = start;

pq->OSQSize = size;

pq->OSQEntries = 0;

pevent->OSEventType = OS_EVENT_TYPE_Q;

pevent->OSEventCnt = 0;

pevent->OSEventPtr = pq;

OS_EventWaitListInit(pevent); /* 初始化等待列表 */

} else {

pevent->OSEventPtr = (void *)OSEventFreeList; /* Nn error */

OSEventFreeList = pevent;

OS_EXIT_CRITICAL();

/////////********

pevent = (OS_EVENT *)0;

*******///////

}

}

return (pevent);

}

流程图

1 OSQCreate ()流程图就绪表 Ready List

 

1.3.2 OSQpend()等待一个消息队列中的消息

源码分析

void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

void *msg;

OS_Q *pq;

 

if (OSIntNesting > 0) { /* See if called from ISR ... */

*err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */

return ((void *)0);

}

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) { /* 查看 ECB 是否可用 */

*err = OS_ERR_PEVENT_NULL;

return ((void *)0);

}

if (pevent->OSEventType != OS_EVENT_TYPE_Q) { / * 查看 ECB 的类型是否为队列 */

*err = OS_ERR_EVENT_TYPE;

return ((void *)0);

}

#endif

OS_ENTER_CRITICAL();

pq = (OS_Q *)pevent->OSEventPtr; /* ECB 指向消息队列 */

if (pq->OSQEntries > 0) { /* 查看是否有消息在队列中 */

msg = *pq->OSQOut++; /* 是则最后进的消息出队列 */

pq->OSQEntries--; /* 消息数减 1 */

if (pq->OSQOut == pq->OSQEnd) { /* 如果出队列指针在队尾则将其指向队头 */

pq->OSQOut = pq->OSQStart;

}

OS_EXIT_CRITICAL();

*err = OS_NO_ERR;

return (msg); /* 返回收到的消息 */

}

OSTCBCur->OSTCBStat |= OS_STAT_Q; /* 任务需要等待一个消息 */

OSTCBCur->OSTCBDly = timeout; /* 设置超时时间 */

OS_EventTaskWait(pevent); /* 挂起任务直到超时或消息到来 */

OS_EXIT_CRITICAL();

OS_Sched(); /* Find next highest priority task ready to run */

OS_ENTER_CRITICAL();

msg = OSTCBCur->OSTCBMsg;

if (msg != (void *)0) { /* 如果得到消息 */

OSTCBCur->OSTCBMsg = (void *)0; /* TCB 中获取 msg */

OSTCBCur->OSTCBStat = OS_STAT_RDY; /* 设置状态为 ready */

OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* 不再等待事件发生 */

OS_EXIT_CRITICAL();

*err = OS_NO_ERR;

return (msg); /* Return message received */

}

OS_EventTO(pevent); /* 超时处理 */

OS_EXIT_CRITICAL();

*err = OS_TIMEOUT; /* Indicate a timeout occured */

return ((void *)0); /* No message received */

}

 

1.3.3 OSQPost() 向消息队列发送一个信息( FIFO方式)

源码分析
  1. OS_EVENT *pevent

  2. void *msg

#if OS_Q_POST_EN > 0

INT8U OSQPost (OS_EVENT *pevent, void *msg)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

OS_Q *pq;

 

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */

return (OS_ERR_PEVENT_NULL);

}

if (msg == (void *)0) { /* 确保我们不是在发送无效消息 */

return (OS_ERR_POST_NULL_PTR);

}

if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* 查看事件类型是否为队列 */

return (OS_ERR_EVENT_TYPE);

}

#endif

OS_ENTER_CRITICAL();

if (pevent->OSEventGrp != 0x00) { /* 查看是否有任务在等待 */

OS_EventTaskRdy(pevent, msg, OS_STAT_Q); /* 令高优先级等待任务就绪 */

OS_EXIT_CRITICAL();

OS_Sched(); /* Find highest priority task ready to run */

return (OS_NO_ERR);

}

pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */

if (pq->OSQEntries >= pq->OSQSize) { /* Make sure queue is not full */

OS_EXIT_CRITICAL();

return (OS_Q_FULL);

}

*pq->OSQIn++ = msg; /* Insert message into queue */

pq->OSQEntries++; /* Update the nbr of entries in the queue */

if (pq->OSQIn == pq->OSQEnd) { /* Wrap IN ptr if we are at end of queue */

pq->OSQIn = pq->OSQStart;

}

OS_EXIT_CRITICAL();

return (OS_NO_ERR);

}

#endif

 

1.3.4 OSQPostFront ()向消息队列发送一个消息(后进先出 LIFO

源码分析
  1. OS_EVENT *pevent

  2. void *msg

#if OS_Q_POST_FRONT_EN > 0

INT8U OSQPostFront (OS_EVENT *pevent, void *msg)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

OS_Q *pq;

 

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) { /* 查看 ECB 是否可用 */

return (OS_ERR_PEVENT_NULL);

}

if (msg == (void *)0) { /* 确定消息可用 */

return (OS_ERR_POST_NULL_PTR);

}

if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* 查看事件类型 */

return (OS_ERR_EVENT_TYPE);

}

#endif

OS_ENTER_CRITICAL();

if (pevent->OSEventGrp != 0x00) { /* See if any task pending on queue */

OS_EventTaskRdy(pevent, msg, OS_STAT_Q); /* Ready highest priority task waiting on event*/

OS_EXIT_CRITICAL();

OS_Sched(); /* Find highest priority task ready to run */

return (OS_NO_ERR);

}

pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */

if (pq->OSQEntries >= pq->OSQSize) { /* Make sure queue is not full */

OS_EXIT_CRITICAL();

return (OS_Q_FULL);

}

if (pq->OSQOut == pq->OSQStart) { /* 如果 out 指针指向开头 */

pq->OSQOut = pq->OSQEnd; /* 令其指向队尾,保证 LIFO */

}

pq->OSQOut--; /* 注意后进先出的 out 指针是减减 */

*pq->OSQOut = msg; /* Insert message into queue */

pq->OSQEntries++; /* Update the nbr of entries in the queue */

OS_EXIT_CRITICAL();

return (OS_NO_ERR);

}

#endif

 

1.3.5 OSQAccept()无等待地从一个消息队列中取得消息

 

#if OS_Q_ACCEPT_EN > 0

void *OSQAccept (OS_EVENT *pevent)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

void *msg;

OS_Q *pq;

 

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) { /* 查看 ECB 是否有效 */

return ((void *)0);

}

if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* 查看类型是否有效 */

return ((void *)0);

}

#endif

OS_ENTER_CRITICAL();

pq = (OS_Q *)pevent->OSEventPtr; /* Point at queue control block */

if (pq->OSQEntries > 0) { /* See if any messages in the queue */

msg = *pq->OSQOut++; /* Yes, extract oldest message from the queue */

pq->OSQEntries--; /* Update the number of entries in the queue */

if (pq->OSQOut == pq->OSQEnd) { /* Wrap OUT pointer if we are at the end of the queue */

pq->OSQOut = pq->OSQStart;

}

} else {

msg = (void *)0; /* Queue is empty */

}

OS_EXIT_CRITICAL();

return (msg); /* Return message received (or NULL) */

}

#endif

 

1.3.6 OSQQuery() 查询一个消息队列状态

源码分析
  1. OS_EVENT *pevent

  2. OS_Q_DATA *pdata

typedef struct {

void *OSMsg; /* Pointer to next message to be extracted from queue */

INT16U OSNMsgs; /* Number of messages in message queue */

INT16U OSQSize; /* Size of message queue */

INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */

INT8U OSEventGrp; /* Group corresponding to tasks waiting for event to occur */

} OS_Q_DATA;

 

 

 

#if OS_Q_QUERY_EN > 0

INT8U OSQQuery (OS_EVENT *pevent, OS_Q_DATA *pdata)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

OS_Q *pq;

INT8U *psrc;

INT8U *pdest;

 

 

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */

return (OS_ERR_PEVENT_NULL);

}

if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */

return (OS_ERR_EVENT_TYPE);

}

#endif

OS_ENTER_CRITICAL();

pdata->OSEventGrp = pevent->OSEventGrp; /* Copy message queue wait list */

psrc = &pevent->OSEventTbl[0];

pdest = &pdata->OSEventTbl[0];

#if OS_EVENT_TBL_SIZE > 0

*pdest++ = *psrc++;

#endif

#if OS_EVENT_TBL_SIZE > 1

*pdest++ = *psrc++;

#endif

#if OS_EVENT_TBL_SIZE > 2

*pdest++ = *psrc++;

#endif

#if OS_EVENT_TBL_SIZE > 3

*pdest++ = *psrc++;

#endif

#if OS_EVENT_TBL_SIZE > 4

*pdest++ = *psrc++;

#endif

#if OS_EVENT_TBL_SIZE > 5

*pdest++ = *psrc++;

#endif

#if OS_EVENT_TBL_SIZE > 6

*pdest++ = *psrc++;

#endif

#if OS_EVENT_TBL_SIZE > 7

*pdest = *psrc;

#endif

pq = (OS_Q *)pevent->OSEventPtr;

if (pq->OSQEntries > 0) {

pdata->OSMsg = *pq->OSQOut; /* Get next message to return if available */

} else {

pdata->OSMsg = (void *)0;

}

pdata->OSNMsgs = pq->OSQEntries;

pdata->OSQSize = pq->OSQSize;

OS_EXIT_CRITICAL();

return (OS_NO_ERR);

}

#endif

 

1.3.7 OSQFlush()清空一个队列

 

#if OS_Q_FLUSH_EN > 0

INT8U OSQFlush (OS_EVENT *pevent)

{

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR cpu_sr;

#endif

OS_Q *pq;

 

#if OS_ARG_CHK_EN > 0

if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */

return (OS_ERR_PEVENT_NULL);

}

if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */

return (OS_ERR_EVENT_TYPE);

}

#endif

OS_ENTER_CRITICAL();

pq = (OS_Q *)pevent->OSEventPtr; /* 指向队列 */

pq->OSQIn = pq->OSQStart; /* 不一定要从队头开始 */

pq->OSQOut = pq->OSQStart;

pq->OSQEntries = 0;

OS_EXIT_CRITICAL();

return (OS_NO_ERR);

}

#endif

 

2.就绪表 Ready List

整个 uCOS-II 的任务就绪管理用一个 8位数组 OSRdyTbl[8]存储。他存储了对应的 64个优先级

2.1 就绪表示意图

 

 

其中若某一优先级就绪,则相应位( 0-63)置 1 OSRdyGrp是优先级分组的标志。它的每一位代表该优先级组是否有就绪任务,若某一组有就绪态,则相应为置 1,否则为 0

另外有两个用于查询的表

这个表分别记录了 8 位数据的每一位为 1 的情况。如果我要对 Data = 0x1F 的第 5 位置 1 ,则可以用 Data |= OSMapTbl[3] .

INT8U const OSMapTbl[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};

 

这个表利用了空间换时间的方法提供最高优先级任务的查询工作。它可以让我们不用去遍历就绪表而直接用查表的方法进行查询。

INT8U const OSUnMapTbl[] = {

0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x00 to 0x0F */

4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x10 to 0x1F */

5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x20 to 0x2F */

4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x30 to 0x3F */

6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x40 to 0x4F */

4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x50 to 0x5F */

5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x60 to 0x6F */

4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x70 to 0x7F */

7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x80 to 0x8F */

4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x90 to 0x9F */

5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xA0 to 0xAF */

4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xB0 to 0xBF */

6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xC0 to 0xCF */

4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xD0 to 0xDF */

5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xE0 to 0xEF */

4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /* 0xF0 to 0xFF */

};

2.2就绪表最高优先级查询方法

设计到三个变量:

  1. OSRdyGrp 用于优先级存储分组情况,每位表示该组是否有就绪任务

  2. OSRdyTbl[n] 表示第 n 组的就绪任务的具体就绪情况情况

  3. OSUnMapTbl[] 就绪表查表用

  4. X 用于存储所在组的数据

  5. Y 用于存储在组内的位置的数据

OSRdyTbl[]里面存储了当前所有就绪的任务情况。我们要找到优先级最高的一个任务号,通常需要采用遍历的方法,而建立这个表以后则只需要查询即可。

X = OSUnMapTbl[OSRdyGrp] ;

Y = OSUnMapTbl[X];

Prio = X<<3 + Y;

2.3OSUnMapTbl[]表建立方法

也就是说通过 OSRdyGrp我们就可以找到最高就绪优先级的任务。

这个表的建立是这样的:首先查找 OSRdyGrp,找到有就绪任务的优先级最高的组(为 1的最低位)。若 OSRdyGrp 0位为 1,计 OSRdyGrp = xxxxxxx1 ,则无论高 7位置何如,查表后返回值都应该是 0(第 0组就绪任务), OSRdyGrp 28 个值,则建立一个 256大小的数组来存储。那么这个数组的 xxxxxxx1位都应该是 0。而若 OSRdyGrp 1位为 1,第 0位为 0,即 xxxxxx10,则无论高 6位置何值,查表返回值都应该是 1(第 1组就绪任务),这个数组的 xxxxxx10个值都应该是 1。以此类推,可以完成整个表的建立。

通过该表进行查询后即可得到相应的优先级值。

/////////////////****************

注意当 OSRdyGrp = 0x00时,即没有任务就绪时,查找到的优先级为 0.

*****************/////////////////

 

 

2.4从就绪表中去除某优先级

从就绪表中去除某优先级(即将对应优先级号的位置 0

OSRdyTbl[prio>>3] &= ~OSMapTbl[Prio&0x07];

由于这种操作可能导致某优先级组全为 0的情况,会影响 OSRdyGrp,所以还要对其进行判断。

If ( OSRdyTbl[prio>>3] &= ~OSMapTbl[Prio&0x07]) & OSMapTbl[prio&0x07] == 0)

{

OSRdyGrp &= ~ OSMapTbl[prio>>3] ;

}

以上程序完成了从就绪列表去除优先级和更新 OSRdyGrp 两件事。

 

3.任务状态

#define OS_STAT_RDY 0x00 /* Ready to run */

#define OS_STAT_SEM 0x01 /* Pending on semaphore */

#define OS_STAT_MBOX 0x02 /* Pending on mailbox */

#define OS_STAT_Q 0x04 /* Pending on queue */

#define OS_STAT_SUSPEND 0x08 /* Task is suspended */

#define OS_STAT_MUTEX 0x10 /* Pending on mutual exclusion semaphore */

#define OS_STAT_FLAG 0x20 /* Pending on event flag group */

 

4.

 

#if (OS_EVENT_EN > 0) && (OS_MAX_EVENTS > 0)

typedef struct {

INT8U OSEventType; /* Type of event control block (see OS_EVENT_TYPE_???) */

INT8U OSEventGrp; /* Group corresponding to tasks waiting for event to occur */

INT16U OSEventCnt; /* Semaphore Count (not used if other EVENT type) */

void *OSEventPtr; /* Pointer to message or queue structure */

INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */

} OS_EVENT;

#endif

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值