本帖最后由 john_lee 于 2010-11-22 01:27 编辑
虽然我并不赞同飞船的说法,但我觉得这个CoOS可能有些瑕疵。
这是CoOS中的一个函数(摘录自CoOS源码,本人一字未改):-
- /**
- *******************************************************************************
- * @brief Pend for a mail
- * @param[in] id Event ID.
- * @param[in] timeout The longest time for writting mail.
- * @param[out] perr A pointer to error code.
- * @retval NULL
- * @retval A pointer to mail accept.
- *
- * @par Description
- * @details This function is called to wait for a mail.
- * @note
- *******************************************************************************
- */
- void* CoPendQueueMail(OS_EventID id,U32 timeout,StatusType* perr)
- {
- P_ECB pecb;
- P_QCB pqcb;
- P_OSTCB curTCB;
- void* pmail;
- if(OSIntNesting > 0) /* If the caller is ISR */
- {
- *perr = E_CALL;
- return NULL;
- }
- #if CFG_PAR_CHECKOUT_EN >0
- if(id >= CFG_MAX_EVENT)
- {
- *perr = E_INVALID_ID; /* Invalid event id,return error */
- return NULL;
- }
- #endif
- pecb = &EventTbl[id];
- #if CFG_PAR_CHECKOUT_EN >0
- if(pecb->eventType != EVENT_TYPE_QUEUE) /* The event type is not queue */
- {
- *perr = E_INVALID_ID;
- return NULL;
- }
- #endif
- if(OSSchedLock != 0) /* Judge schedule is locked or not? */
- {
- *perr = E_OS_IN_LOCK; /* Schedule is locked,return error */
- return NULL;
- }
- pqcb = (P_QCB)pecb->eventPtr; /* Point at queue control block */
-
- if(pqcb->qSize != 0) /* If there are any messages in the queue */
- {
- /* Extract oldest message from the queue */
- pmail = *(pqcb->qStart + pqcb->head);
- pqcb->head++; /* Update the queue head */
- pqcb->qSize--; /* Update the number of messages in the queue */
- if(pqcb->head == pqcb->qMaxSize)/* Check queue head */
- {
- pqcb->head = 0;
- }
- *perr = E_OK;
- return pmail; /* Return message received */
- }
- else /* If there is no message in the queue*/
- {
- curTCB = TCBRunning;
- if(timeout == 0) /* If time-out is not configured */
- {
- /* Block current task until the event occur */
- EventTaskToWait(pecb,curTCB);
-
- /* Have recived message or the queue have been deleted */
- pmail = curTCB->pmail;
- curTCB->pmail = NULL;
- *perr = E_OK;
- return pmail; /* Return message received or NULL */
- }
- else /* If time-out is configured */
- {
- OsSchedLock();
-
- /* Block current task until event or timeout occurs */
- EventTaskToWait(pecb,curTCB);
- InsertDelayList(curTCB,timeout);
- OsSchedUnlock();
- if(curTCB->pmail == NULL) /* If time-out occurred */
- {
- *perr = E_TIMEOUT;
- return NULL;
- }
- else /* If event occured */
- {
- pmail = curTCB->pmail;
- curTCB->pmail = NULL;
- *perr = E_OK;
- return pmail; /* Return message received or NULL */
- }
- }
- }
- }
这个函数中,pqcb的head, qSize应该属于临界资源,但我没有看到任何保护这些资源的机制。
可以想象一下,一个任务(A)执行到了这一步:假设qSize的当前值为2,当qSize的值从RAM中装载到寄存器后,这时出现了一个中断,这个中断READY了另外一个任务(B),而这个任务(B)又执行了对此队列的post mail动作,在那里,qSize被+1变为了3, 当调度器将CPU重新交给了任务(A)时,任务(A)并不知道qSize在RAM中的值已经发生了变化,而继续用已经装载到寄存器中的旧值2进行-1, 得到了一个值1(当然这是错误的),并且写回到qSize中。
系统将在此后的某个时刻崩溃。
|