9509238 发表于 2010-5-12 09:50:39

对不起,还是那个BUG!

这次的标题应该不是太显眼了吧。。。
RTT管理员对我提出的“rt_tick_increase()函数的不妥”似乎不以为然,熟视无睹,都提出来了,还不仔细更正,技术问题岂能如此轻率!?

我再给你分析一遍,rt_tick_increase()函数的调用关系跟踪如下(-> 符号表示调用关系, == 符号表示等同调用关系):
rt_tick_increase() -> rt_timer_check() -> t->timeout_func(t->parameter) == rt_thread_timeout(thread)
-> rt_schedule() -> {rt_current_thread = to_thread;}
到此,rt_current_thread已经被改变了!而当rt_timer_check()函数返回之后,rt_tick_increase()函数会调用
rt_thread_self()来获得当前线程,其实这时候它返回的并不是“被中断的当前线程”,而是rt_thread_timeout()函数引起的某个新的就绪线程。
所以对它进行{-- thread->remaining_tick;}操作是错误的!

如果我有分析不对的,也请版主指出,只是不要封贴!

aozima 发表于 2010-5-12 10:10:33

我斗胆帮楼主改下内容,如果楼主能接受,我想这是一个很好的讨论.


标题: 再次讨论 RTT- 定时器tick的不妥

rt_tick_increase()函数的调用关系跟踪如下(-> 符号表示调用关系, == 符号表示等同调用关系):
rt_tick_increase() -> rt_timer_check() -> t->timeout_func(t->parameter) == rt_thread_timeout(thread)
-> rt_schedule() -> {rt_current_thread = to_thread;}
到此,rt_current_thread已经被改变了!而当rt_timer_check()函数返回之后,rt_tick_increase()函数会调用
rt_thread_self()来获得当前线程,其实这时候它返回的并不是“被中断的当前线程”,而是rt_thread_timeout() 函数引起的某个新的就绪线程。
所以对它进行{-- thread->remaining_tick;}操作是错误的!


另贴一个FFXZ的公开邮件:(我未经FFXZ同意就公开了,图中隐去的是各人的ID,并非有意掩饰什么.)
http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_553342.jpg
(原文件名:mail-ffxz.jpg)

ffxz 发表于 2010-5-12 10:44:30

回复【楼主位】9509238
这次的标题应该不是太显眼了吧。。。
rtt管理员对我提出的“rt_tick_increase()函数的不妥”似乎不以为然,熟视无睹,都提出来了,还不仔细更正,技术问题岂能如此轻率!?
我再给你分析一遍,rt_tick_increase()函数的调用关系跟踪如下(-> 符号表示调用关系, == 符号表示等同调用关系):
rt_tick_increase() -> rt_timer_check() -> t->timeout_func(t->parameter) == rt_thread_timeout(thread)
-> rt_schedule() -> {rt_current_thread = to_thread;}
到此,rt_current_thread已经被改变了!而当rt_timer_check()函数返回之后,rt_tick_inc......
-----------------------------------------------------------------------

看来我上次对你说的rt_thread_self()的问题理解有误,抱歉。(毕竟不是每一次看问题都能正确理解的,所以当理解不对时也还请及时指出。当时已经给你回帖了,只是后来你并没针对这个问题继续讨论下去,所以还以为就如我理解的那样,没有问题)

这个问题应该是rt_tick_increase() 和 rt_thread_self()结合起来用时才发生?(即rt_tick_increase()的函数调用过程中调用了rt_thread_self())可以考虑把remain tick放到timer_check前面进行,只是这样依然不能避免问题的出现:rt_tick_increase是在中断中被调用,但Cortex-M3和原来的ARM有很大的不同,支持了中断抢占,也就是说,如果这个地方发生了中断抢占,那么也可能会让新的(还未被运行的)线程提前消耗掉它的一个tick数。

针对这类情况,能否给出个测试代码?这样,当修正了时也能够进行回归测试。

9509238 发表于 2010-5-12 11:45:57

回复【2楼】ffxz
-----------------------------------------------------------------------

这回比较爽快,我们别说废话就行。

把rt_timer_check()放到最后面是可以解决问题的。
你说的中断抢占,是有个优先级前提的,相同优先级的中断永远不会发生抢占,所以tick中断不会抢占tick中断自己。而remaining_tick计数器只会在tick中断中被自减。

ffxz 发表于 2010-5-12 11:55:13

回复【3楼】9509238
回复【2楼】ffxz
-----------------------------------------------------------------------
这回比较爽快,我们别说废话就行。
把rt_timer_check()放到最后面是可以解决问题的。
你说的中断抢占,是有个优先级前提的,相同优先级的中断永远不会发生抢占,所以tick中断不会抢占tick中断自己。而remaining_tick计数器只会在tick中断中被自减。
-----------------------------------------------------------------------

不是说OS Tick中断,而是其他中断,其他中断也有可能触发线程切换。

现在越来越觉得太有必要加入一个类似最高级优先级线程的处理了,OS相关的东西都由这个最高优先级线程去执行。

9509238 发表于 2010-5-12 14:34:13

最高优先级线程的存在,能缓解很多关中断压力。但是势必造成更多的线程切换代价,这需要权衡啊!
其它抢占的中断,虽然能触发线程切换,但没有做事实上的切换动作,因为有rt_interrupt_nest计数器的存在。
不管有没有抢占的中断到来,只要把tick中断的优先级设置为最低就可以避免了。

9509238 发表于 2010-5-12 14:40:53

ffxz说得对,即使tick中断优先级最低,还是会出现同样的问题。
可以说,这就是一个不妥之处,并不是一个bug级别的东西。

ffxz 发表于 2010-5-12 16:21:11

使用最高优先级线程的方式应该能够解决这个问题,而线程切换的代价应该还行,只会有实际的事情要处理时才最终切换过去执行。

而且最高优先级线程(或叫做高级中断服务例程)可以把目前的一些线程,例如erx、etx取代,同时也会减少(或完全去掉)系统的关中断时间,提高系统的实时相应能力。

mbbill 发表于 2010-5-12 16:44:17

回复【5楼】9509238
最高优先级线程的存在,能缓解很多关中断压力。但是势必造成更多的线程切换代价,这需要权衡啊!
其它抢占的中断,虽然能触发线程切换,但没有做事实上的切换动作,因为有rt_interrupt_nest计数器的存在。
不管有没有抢占的中断到来,只要把tick中断的优先级设置为最低就可以避免了。
-----------------------------------------------------------------------

rt_interrupt_nest没有用的,执行rt_rescule()函数成功以后rt_current_thread已经变了,当前线程上下文和rt_current_thread变量并不是完全原子操作的,这里面嵌进一些中断是很容易出问题。
还有一个问题就是,在中断可以被抢占的情况下所有内核对象都必须互斥访问,而内核对象是挂在链表上,所以整个链表的读写必须互斥起来,比如我在低优先级的中断里面从某个链表上拆一个对象出来的时候,被高优先级中断打断,然后又去访问这个链表就出问题了。
用最高优先级来做这件事应该是个很好的解决方法,像lwip那样中断不去访问任何一个内核对象,而只把消息打包发给那个线程,线程可以保证执行的原子性和顺序性,代码也可以写得很干净。

btw,9509238,我怎么还是觉得你说话很冲呢?啥叫“别废话就行”啊,你要别人客客气气对你,你自己先客气一点行不?

gzhuli 发表于 2010-5-12 17:11:53

把rt_current_thread放在真正context switch时再修改?

ffxz 发表于 2010-5-21 18:02:57

那个tick溢出的问题基本上已经修正,在把tick变量单位更改为rt_uint8_t测试通过(增加了一个链表,并不需要把每个timer的tick单位更改为64位)。

同时还包括timer_timeout时的一个问题:timer timeout时持有链表有些问题,可能上次拿到的节点已经被超时函数删除。

修正会尽快更新到0.4.x版本上,没问题后再更新到0.3.1版本上。
页: [1]
查看完整版本: 对不起,还是那个BUG!