1.1.1 OSSemQuery() 信号量查询
源码分析
INT8U OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *pdata)
-
OS_EVENT *pevent 要查询的信号量 ECB 指针
-
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)
-
Void *msg 携带的信息
说明:
-
OSMboxCreate 所携带的变量是 void *msg , 而 OSSemCreate 携带的是 INT16U cnt ,邮箱没有 OSEventCnt 变量,都置为 0 ,但要 OSEventPtr 指向 msg 。
-
邮箱一旦建立,是不能被删除的
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方式)
源码分析
-
OS_EVENT *pevent
-
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)
源码分析
-
OS_EVENT *pevent
-
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() 查询一个消息队列状态
源码分析
-
OS_EVENT *pevent
-
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就绪表最高优先级查询方法
设计到三个变量:
-
OSRdyGrp 用于优先级存储分组情况,每位表示该组是否有就绪任务
-
OSRdyTbl[n] 表示第 n 组的就绪任务的具体就绪情况情况
-
OSUnMapTbl[] 就绪表查表用
-
X 用于存储所在组的数据
-
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
本文详细分析了uC/OS-II操作系统中的信号量查询OSSemQuery()、邮箱创建OSMboxCreate()、邮箱接收OSMboxPend()、发送OSMboxPost()以及消息队列的相关函数,包括创建、接收、发送和查询等操作。同时,介绍了就绪表的管理,包括就绪表示意图、查询方法及去除优先级的逻辑。
2284

被折叠的 条评论
为什么被折叠?



