前言
公司的一款产品,使用ucosii操作系统,任务间的整体通讯思路是依赖OSEventPendMulti函数完成不同任务之间的消息传递.而某个任务的OSEventPendMulti函数经常性的收不到特定消息.
分析
分析这个OSEventPendMulti函数等待的事件,一共等待4个事件,分别是两个来自其他任务的事件,和systick每隔200ms发出的空消息邮箱事件(做200ms定时器功能), 以及RTC每隔1秒发出的空消息邮箱事件(做1000ms定时器使用). 其中RTC发出的事件,经常性的收不到.对发消息和收消息处展开分析,最终定位到了问题所在.假定有bug的那个任务为任务L,
RTC中断中一共发送3个消息给到不同的任务,任务L的优先级是最低的.由于RTC是在中断中发消息,消息发送后并不会立即产生调度,而是等到中断退出时才会产生调度.所以中断退出时并不会立即调度到任务L,而是调度到其他优先级更高的任务.
给任务L发送消息时,在发送消息函数内部调用OS_EventTaskRdy 其中ptcb->OSTCBEventMultiRdy = (OS_EVENT *)pevent;任务L保存了这个事件,看到这里,一下子想到,OSEventPendMulti不会单次仅返回一个就绪事件吧.
OS_EventTaskRdy函数内部.
#if (OS_EVENT_MULTI_EN > 0u)
if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) { /* Remove this task from events' wait lists */
OS_EventTaskRemoveMulti(ptcb, ptcb->OSTCBEventMultiPtr);
ptcb->OSTCBEventMultiPtr = (OS_EVENT **)0; /* No longer pending on multi list */
ptcb->OSTCBEventMultiRdy = (OS_EVENT *)pevent;/* Return event as first multi-pend event ready*/
}
#endif
经查验果然如此.问题到此逐渐明朗,任务L虽然已就绪,但是还要等待其他高优先级的任务调度完成才能调度.而此时其他高优先级的任务运行又比较耗时.所以任务还没有得到调度时. systick中断中又向任务发送了一个消息, 导致OSTCBCur->OSTCBEventMultiRdy被新的消息覆盖. 等到任务L得以调度时,RTC发出的消息已经被覆盖,所以没有得以运行.
switch (OSTCBCur->OSTCBStatPend) { /* Handle event posted, aborted, or timed-out */
case OS_STAT_PEND_OK:
case OS_STAT_PEND_ABORT:
// 获取到OSTCBEventMultiRdy指向的事件.
pevent = OSTCBCur->OSTCBEventMultiRdy;
if (pevent != (OS_EVENT *)0) { /* If task event ptr != NULL, ... */
*pevents_rdy++ = pevent; /* ... return available event ... */
*pevents_rdy = (OS_EVENT *)0; /* ... & NULL terminate return event array */
events_rdy_nbr = 1;
} else { /* Else NO event available, handle as timeout */
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_TO;
OS_EventTaskRemoveMulti(OSTCBCur, pevents_pend);
}
break;
解决
问题的解决方案有很多,知道了OSEventPendMulti的这个特性,在使用时就要多加注意,在这个项目中因为收到消息处理的事务并不多,我就直接删除了RTC发送的那个消息.让L任务中每隔一秒运行的事件,放在200ms事件中累加5次后运行。
|