typedef struct os_event {
INT8U OSEventType; /* Type of event control block (see OS_EVENT_TYPE_xxxx) */
void *OSEventPtr; /* Pointer to message or queue structure */
// 不用的时候将OSEventTbl[OS_MAX_EVENTS]连成链表,被使用时pevent->OSEventPtr = pq;pq是OS_Q *型。见OSQCreate
INT16U OSEventCnt; /* Semaphore Count (not used if other EVENT type) */
#if OS_LOWEST_PRIO <= 63
INT8U OSEventGrp; /* Group corresponding to tasks waiting for event to occur */
INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */
#else
INT16U OSEventGrp; /* Group corresponding to tasks waiting for event to occur */
INT16U OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */
#endif
#if OS_EVENT_NAME_SIZE > 1
INT8U OSEventName[OS_EVENT_NAME_SIZE];
#endif
} OS_EVENT;
ucos_ii.h
OS_EXT OS_EVENT *OSEventFreeList; /* Pointer to list of free EVENT control blocks */
OS_EXT OS_EVENT OSEventTbl[OS_MAX_EVENTS];/* Table of EVENT control blocks */
os_core.c中static void OS_InitEventList (void)有OSEventFreeList = &OSEventTbl[0];
typedef struct os_q { /* QUEUE CONTROL BLOCK */
struct os_q *OSQPtr; /* Link to next queue control block in list of free blocks */将OSQTbl[OS_MAX_QS]链接成链表(OS_QInit中)
void **OSQStart; /* Pointer to start of queue data */
void **OSQEnd; /* Pointer to end of queue data */
void **OSQIn; /* Pointer to where next message will be inserted in the Q */
void **OSQOut; /* Pointer to where next message will be extracted from the Q */
INT16U OSQSize; /* Size of queue (maximum number of entries) */
INT16U OSQEntries; /* Current number of entries in the queue */
} OS_Q;
ucos_ii.h中
OS_EXT OS_Q *OSQFreeList; /* Pointer to list of free QUEUE control blocks */
OS_EXT OS_Q OSQTbl[OS_MAX_QS]; /* Table of QUEUE control blocks */
os_q.c中void OS_QInit (void)有OSQFreeList = &OSQTbl[0]; /* Only ONE queue! */
void OS_QInit (void)
{
OSQFreeList = &OSQTbl[0]; /* Only ONE queue! */
OSQFreeList->OSQPtr = (OS_Q *)0;
INT16U i;
OS_Q *pq1;
OS_Q *pq2;
OS_MemClr((INT8U *)&OSQTbl[0], sizeof(OSQTbl)); /* Clear the queue table */
pq1 = &OSQTbl[0];
pq2 = &OSQTbl[1];
for (i = 0; i < (OS_MAX_QS - 1); i++) { /* Init. list of free QUEUE control blocks */
pq1->OSQPtr = pq2;
pq1++;
pq2++;
}
pq1->OSQPtr = (OS_Q *)0;
OSQFreeList = &OSQTbl[0];
}
typedef struct os_q_data { //此结构有什么用????????
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 */
#if OS_LOWEST_PRIO <= 63
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 */
#else
INT16U OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */
INT16U OSEventGrp; /* Group corresponding to tasks waiting for event to occur */
#endif
} OS_Q_DATA;
os_core.c中
static void OS_InitEventList (void)
{
#if (OS_EVENT_EN) && (OS_MAX_EVENTS > 0)
#if (OS_MAX_EVENTS > 1)
INT16U i;
OS_EVENT *pevent1;
OS_EVENT *pevent2;
OS_MemClr((INT8U *)&OSEventTbl[0], sizeof(OSEventTbl)); /* Clear the event table */
pevent1 = &OSEventTbl[0];
pevent2 = &OSEventTbl[1];
for (i = 0; i < (OS_MAX_EVENTS - 1); i++) { /* Init. list of free EVENT control blocks */
pevent1->OSEventType = OS_EVENT_TYPE_UNUSED;
pevent1->OSEventPtr = pevent2; //将OSEventTbl[OS_MAX_EVENTS]连成链表
// OS_EXT OS_EVENT OSEventTbl[OS_MAX_EVENTS];/* Table of EVENT control blocks */
pevent1++;
pevent2++;
}
pevent1->OSEventType = OS_EVENT_TYPE_UNUSED;
pevent1->OSEventPtr = (OS_EVENT *)0;
OSEventFreeList = &OSEventTbl[0];
#endif
#endif
}
OS_EVENT *OSQCreate (void **start, INT16U size)
{
OS_EVENT *pevent;
OS_Q *pq;
OS_ENTER_CRITICAL();
pevent = OSEventFreeList; /* Get next free event control block */
OS_EXIT_CRITICAL();
if (pevent != (OS_EVENT *)0)
{
/* See if we have an event control block */
OS_ENTER_CRITICAL();
pq = OSQFreeList; /* Get a free queue control block */
if (pq != (OS_Q *)0)
{ /* Were we able to get a queue control block ? */
OSQFreeList = OSQFreeList->OSQPtr; /* Yes, Adjust free list pointer to next free*/
OS_EXIT_CRITICAL();
pq->OSQStart = start; /* Initialize the queue */
pq->OSQEnd = &start[size];
pq->OSQIn = start; //post有消息从此插入
pq->OSQOut = start; // pend 请求消息从此取出
pq->OSQSize = size;
pq->OSQEntries = 0;
pevent->OSEventType = OS_EVENT_TYPE_Q;
pevent->OSEventCnt = 0;
pevent->OSEventPtr = pq; //这个指针之前是用来串成链表的。现在换用途了。见结构体的解释
OS_EventWaitListInit(pevent); /* Initalize the wait list */
}
else
{
pevent->OSEventPtr = (void *)OSEventFreeList; /* No, Return event control block on error */
OSEventFreeList = pevent;
OS_EXIT_CRITICAL();
pevent = (OS_EVENT *)0;
}
}
return (pevent); //将事件头指针通过函数返回值返回给程序员用
}
/*
*********************************************************************************************************
* INITIALIZE EVENT CONTROL BLOCK'S WAIT LIST
*
* Description: This function is called by other uC/OS-II services to initialize the event wait list.
*
* Arguments : pevent is a pointer to the event control block allocated to the event.
*
* Returns : none
*
* Note : This function is INTERNAL to uC/OS-II and your application should not call it.
*********************************************************************************************************
*/
os_core.c
void OS_EventWaitListInit (OS_EVENT *pevent)
{
#if OS_LOWEST_PRIO <= 63
INT8U *ptbl;
#else
INT16U *ptbl;
#endif
INT8U i;
pevent->OSEventGrp = 0; /* No task waiting on event */
ptbl = &pevent->OSEventTbl[0];
for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
*ptbl++ = 0;
}
}
/*
*********************************************************************************************************
* MAKE TASK WAIT FOR EVENT TO OCCUR
*
* Description: This function is called by other uC/OS-II services to suspend a task because an event has
* not occurred.
*
* Arguments : pevent is a pointer to the event control block for which the task will be waiting for.
*
* Returns : none
*
* Note : This function is INTERNAL to uC/OS-II and your application should not call it.
*********************************************************************************************************
*/
os_core.c
void OS_EventTaskWait (OS_EVENT *pevent)
{
INT8U y;
OSTCBCur->OSTCBEventPtr = pevent; /* Store pointer to event control block in TCB */
//将pevent绑到当前任务TCB的OSTCBEventPtr 成员上。
y = OSTCBCur->OSTCBY; /* Task no longer ready */
OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX;
if (OSRdyTbl[y] == 0) {
OSRdyGrp &= ~OSTCBCur->OSTCBBitY; /* Clear event grp bit if this was only task pending */
}
pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; /* Put task in waiting list */这是等待
pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;
//对比函数INT8U OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt)里
// OSRdyGrp |= ptcb->OSTCBBitY; /* Make task ready to run */这是运行,一个等待,一个运行。不同。
// OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
}
/*
*********************************************************************************************************
* MAKE TASK READY TO RUN BASED ON EVENT OCCURING
*
* Description: This function is called by other uC/OS-II services and is used to ready a task that was
* waiting for an event to occur.
*
* Arguments : pevent is a pointer to the event control block corresponding to the event.
*
* pmsg is a pointer to a message. This pointer is used by message oriented services
* such as MAILBOXEs and QUEUEs. The pointer is not used when called by other
* service functions.
*
* msk is a mask that is used to clear the status byte of the TCB. For example,
* OSSemPost() will pass OS_STAT_SEM, OSMboxPost() will pass OS_STAT_MBOX etc.
*
* pend_stat is used to indicate the readied task's pending status:
*
* OS_STAT_PEND_OK Task ready due to a post (or delete), not a timeout or
* an abort.
* OS_STAT_PEND_ABORT Task ready due to an abort.
*
* Returns : none
*
* Note : This function is INTERNAL to uC/OS-II and your application should not call it.
*********************************************************************************************************
*/
os_core.c
INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *pmsg, INT8U msk, INT8U pend_stat)
{
OS_TCB *ptcb;
INT8U x;
INT8U y;
INT8U prio;
#if OS_LOWEST_PRIO <= 63
INT8U bitx;
INT8U bity;
#else
INT16U bitx;
INT16U bity;
INT16U *ptbl;
#endif
//本函数通过pevent带的优先级信息计算出等待这个消息的是哪个优先级的任务。
#if OS_LOWEST_PRIO <= 63
y = OSUnMapTbl[pevent->OSEventGrp]; /* Find HPT waiting for message */
//看看OS_EventTaskWait 函数不难理解吧。
bity = (INT8U)(1 << y);
x = OSUnMapTbl[pevent->OSEventTbl[y]];
bitx = (INT8U)(1 << x);
prio = (INT8U)((y << 3) + x); /* Find priority of task getting the msg */
#else
if ((pevent->OSEventGrp & 0xFF) != 0) { /* Find HPT waiting for message */
y = OSUnMapTbl[pevent->OSEventGrp & 0xFF];
} else {
y = OSUnMapTbl[(pevent->OSEventGrp >> 8) & 0xFF] + 8;
}
bity = (INT16U)(1 << y);
ptbl = &pevent->OSEventTbl[y];
if ((*ptbl & 0xFF) != 0) {
x = OSUnMapTbl[*ptbl & 0xFF];
} else {
x = OSUnMapTbl[(*ptbl >> 8) & 0xFF] + 8;
}
bitx = (INT16U)(1 << x);
prio = (INT8U)((y << 4) + x); /* Find priority of task getting the msg */
#endif
pevent->OSEventTbl[y] &= ~bitx; /* Remove this task from the waiting list */
if (pevent->OSEventTbl[y] == 0) {
pevent->OSEventGrp &= ~bity; /* Clr group bit if this was only task pending */
}
ptcb = OSTCBPrioTbl[prio]; /* Point to this task's OS_TCB */
ptcb->OSTCBDly = 0; /* Prevent OSTimeTick() from readying task */
ptcb->OSTCBEventPtr = (OS_EVENT *)0; /* Unlink ECB from this task */
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
ptcb->OSTCBMsg = pmsg; /* Send message directly to waiting task */
#else
pmsg = pmsg; /* Prevent compiler warning if not used */
#endif
ptcb->OSTCBStatPend = pend_stat; /* Set pend status of post or abort */
ptcb->OSTCBStat &= ~msk; /* Clear bit associated with event type */
if (ptcb->OSTCBStat == OS_STAT_RDY) { /* See if task is ready (could be susp'd) */
OSRdyGrp |= bity; /* Put task in the ready to run list */
//这个优先级的任务就已经进入ready状态了,见《uc/os_II优先级判定表OSUnMapTbl》
OSRdyTbl[y] |= bitx;
}
return (prio);
}
/*
*********************************************************************************************************
* MAKE TASK READY TO RUN BASED ON EVENT TIMEOUT OR ABORT
*
* Description: This function is called by other uC/OS-II services to make a task ready to run because a
* timeout or abort occurred.
*
* Arguments : pevent is a pointer to the event control block which is readying a task.
*
* Returns : none
*
* Note : This function is INTERNAL to uC/OS-II and your application should not call it.
*********************************************************************************************************
*/
os_core.c
void OS_EventTOAbort (OS_EVENT *pevent)//
{
INT8U y;
//本函数不通过pevent带的优先级信息计算出等待这个消息的是哪个优先级的任务。而是任务自己 timeout or abort occurred
y = OSTCBCur->OSTCBY;
pevent->OSEventTbl[y] &= ~OSTCBCur->OSTCBBitX; /* Remove task from wait list */
if (pevent->OSEventTbl[y] == 0x00) {
pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY;
}
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */
OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set status to ready */
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* No longer waiting for event */
}
INT8U OSQPost (OS_EVENT *pevent, void *pmsg)
{
OS_Q *pq;
if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
return (OS_ERR_EVENT_TYPE);
}
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0)
{ /* See if any task pending on queue */
/* Ready highest priority task waiting on event */
(void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
OS_EXIT_CRITICAL();
OS_Sched(); /* Find highest priority task ready to run */
return (OS_ERR_NONE);
}
pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */取出消息OS_Q
if (pq->OSQEntries >= pq->OSQSize) //OSQEntries是进入消息队列中的消息个数
{ /* Make sure queue is not full */
OS_EXIT_CRITICAL();
return (OS_ERR_Q_FULL);
}
*pq->OSQIn++ = pmsg; /* Insert message into queue */
//*pq->OSQIn=pmsg存入消息后 ++是让OSQIn指针指向下一个地址待下一个消息
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 */ 消息队列是循环的链表 满则指回Start
pq->OSQIn = pq->OSQStart;
}
OS_EXIT_CRITICAL();
return (OS_ERR_NONE);
}
void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)
{
void *pmsg;
OS_Q *pq;
OS_ENTER_CRITICAL();
pq = (OS_Q *)pevent->OSEventPtr; /* Point at queue control block */
if (pq->OSQEntries > 0) //有消息在队列中则大于0 OSQEntries是消息队列中的消息总数
{ /* See if any messages in the queue */
pmsg = *pq->OSQOut++; /* Yes, extract oldest message from the queue */
//pmsg=*pq->OSQOut 从消息队列中取出消息 然后++指向下一个待提取的消息
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 */循环链表满则指回Start
pq->OSQOut = pq->OSQStart;
}
OS_EXIT_CRITICAL();
*perr = OS_ERR_NONE;
return (pmsg); /* Return message received */ 将接收到的的消息通过函数返回值返回
}
OSTCBCur->OSTCBStat |= OS_STAT_Q; /* Task will have to pend for a message to be posted */
//OS_TCB{INT8U OSTCBStat;/* Task status */ INT8U OSTCBStatPend; /* Task PEND status }
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; //任务被挂起标志 挂起原因OSTCBCur->OSTCBStat |= OS_STAT_Q
OSTCBCur->OSTCBDly = timeout; /* Load timeout into TCB */
OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */
OS_EXIT_CRITICAL();
OS_Sched(); /* Find next highest priority task ready to run */
OS_ENTER_CRITICAL();
switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */
case OS_STAT_PEND_OK: /* Extract message from TCB (Put there by QPost) */
pmsg = OSTCBCur->OSTCBMsg;
//当下次有消息是 ptcb->OSTCBMsg = pmsg; (在函数post的子函数OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK)中)ptcb->OSTCBEventPtr = (OS_EVENT *)pevent;/* Return event as first multi-pend event ready*/
如果在规定的时间里面收到消息的话,任务将通过OSTCBCur->OSTCBMsg; 传递消息并继续的执行。特别注意,这里使用 OSTCBCur->OSTCBMsg 而不是pevent->OSEventPtr,主要是因为在多任务消息传递的时候, 可以将消息直接的赋值给各个任务的OSTCBCur->OSTCBMsg;
*perr = OS_ERR_NONE;
break;
case OS_STAT_PEND_ABORT:
pmsg = (void *)0;
*perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */
break;
case OS_STAT_PEND_TO:
default:
OS_EventTaskRemove(OSTCBCur, pevent);
pmsg = (void *)0;
*perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO */
break;
}
OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */
#if (OS_EVENT_MULTI_EN > 0)
OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
#endif
OSTCBCur->OSTCBMsg = (void *)0; /* Clear received message */
OS_EXIT_CRITICAL();
return (pmsg); /* Return rec eived message */为什么此处还有返回消息。因没消息被挂起的任务再次接消息是在此处????
}
以下是
* File : OS_Q.C
* By : Jean J. Labrosse
* Version : V2.85
这个版本的OSQPend 看看红色的地方的不同点,对比以下。
/*
*********************************************************************************************************
* PEND ON A QUEUE FOR A MESSAGE
*
* Description: This function waits for a message to be sent to a queue
*
* Arguments : pevent is a pointer to the event control block associated with the desired queue
*
* timeout is an optional timeout period (in clock ticks). If non-zero, your task will
* wait for a message to arrive at the queue up to the amount of time
* specified by this argument. If you specify 0, however, your task will wait
* forever at the specified queue or, until a message arrives.
*
* perr is a pointer to where an error message will be deposited. Possible error
* messages are:
*
* OS_ERR_NONE The call was successful and your task received a
* message.
* OS_ERR_TIMEOUT A message was not received within the specified 'timeout'.
* OS_ERR_PEND_ABORT The wait on the queue was aborted.
* OS_ERR_EVENT_TYPE You didn't pass a pointer to a queue
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
* OS_ERR_PEND_ISR If you called this function from an ISR and the result
* would lead to a suspension.
* OS_ERR_PEND_LOCKED If you called this function with the scheduler is locked
*
* Returns : != (void *)0 is a pointer to the message received
* == (void *)0 if you received a NULL pointer message or,
* if no message was received or,
* if 'pevent' is a NULL pointer or,
* if you didn't pass a pointer to a queue.
*
* Note(s) : As of V2.60, this function allows you to receive NULL pointer messages.
*********************************************************************************************************
*/
void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)
{
void *pmsg;
OS_Q *pq;
INT8U pend_stat;
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
#if OS_ARG_CHK_EN > 0
if (perr == (INT8U *)0) { /* Validate 'perr' */
return ((void *)0);
}
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
*perr = OS_ERR_PEVENT_NULL;
return ((void *)0);
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type */
*perr = OS_ERR_EVENT_TYPE;
return ((void *)0);
}
#endif
if (OSIntNesting > 0) { /* See if called from ISR ... */
*perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
return ((void *)0);
}
if (OSLockNesting > 0) { /* See if called with scheduler locked ... */
*perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */
return ((void *)0);
}
OS_ENTER_CRITICAL();
pq = (OS_Q *)pevent->OSEventPtr; /* Point at queue control block */
if (pq->OSQEntries > 0) { /* See if any messages in the queue */
pmsg = *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;
}
OS_EXIT_CRITICAL();
*perr = OS_ERR_NONE;
return (pmsg); /* Return message received */
}
OSTCBCur->OSTCBStat |= OS_STAT_Q; /* Task will have to pend for a message to be posted */
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
OSTCBCur->OSTCBDly = timeout; /* Load timeout into TCB */
OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */
OS_EXIT_CRITICAL();
OS_Sched(); /* Find next highest priority task ready to run */
OS_ENTER_CRITICAL();
if (OSTCBCur->OSTCBStatPend != OS_STAT_PEND_OK) { /* Was task readied because timed-out or aborted?*/
pend_stat = OSTCBCur->OSTCBStatPend;
OS_EventTOAbort(pevent);//新加的,上面那个版本的函数是这个地方没有这个函数的。
OS_EXIT_CRITICAL();
switch (pend_stat) {
case OS_STAT_PEND_TO:
default:
*perr = OS_ERR_TIMEOUT; /* Indicate a timeout occured */
break;
case OS_STAT_PEND_ABORT:
*perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */
break;
}
return ((void *)0); /* No message received */
}
pmsg = OSTCBCur->OSTCBMsg;/* No, Extract message from TCB (Put there by QPost) */
OSTCBCur->OSTCBMsg = (void *)0;
OSTCBCur->OSTCBStat = OS_STAT_RDY;
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* No longer waiting for event */
OS_EXIT_CRITICAL();
*perr = OS_ERR_NONE;
return (pmsg); /* Return message received */
}