今天要说的,是系统挂起问题。许多作嵌入式软件的团队其实并不了解嵌入式软件的特色,在他们的眼里,只有软件问题;所以出了问题的时候,才开始抱怨这个没有,那个也没有,总之,能在电脑上用的工具方法都没有。其实这些只能怨本身,嵌入式系统不能是个黑盒子,不然创建在上面的应用程序早晚会出问题。并发
先说说系统挂起有哪些特征。函数
Case 1适用Coredump方法解决,Case 2比较复杂,须要根据实际状况处理。我要说的,是针对Case 3 & 4的通用解决方法。工具
开始以前,得先说说多任务系统的切换。因此能切换,离不开两个条件:当前任务主动弃权;当前任务被剥权而强制切换。测试
主动弃权,就是执行系统调用,好比msgq_send,sendto,malloc,fread等函数,这类函数会涉及系统核心或是信号量处理,所以CPU会在用户态和系统态间切换。调用发生时,系统从用户态转为系统态,当前任务即被挂起,放回调度队列;当CPU离开系统态时,调度就可以检查调度队列,激活任务等待队列最前面的任务。而这个最前面的任务,不少时候并非原来的应用。最典型的,就是msgq_send调用。日常作功能测试时,不会有并发的消息,整个处理过程都是线性化的,一个任务处理完,发消息给下一个任务处理,就这样,一个任务接着一个任务,直处处理结束。这时候的系统,任务优先级其实没什么用的,由于任务运行的触发事件就一个,除了那个正在作事的,你们都在等,也只能等。编码
强制切换,须要系统中断来实现,能够是外部硬件中断,也能够是CPU内部的时钟中断。外部硬件中断,好比网口接收到新的数据,就会以中断方式通知CPU接收。中断发生后,当前应用就被被挂起,送回调度队列。中断处理完成后,CPU转入系统模式,而不是回到用户模式,此时天然能够执行调度处理。固然,凡事没有绝对,好比快速中断就不必定是这么作,且各个OS对细节有本身的权衡。时钟中断,包括提供给应用程序的定时器时钟和Tick时钟。定时器时钟是涉及比较多的,通常微小系统里,会不做封装,直接使用。Tick时钟,就是这里要讲的关键了。spa
Tick中断是提供给OS进行任务调度切换用的,以免某些任务长期占据CPU,实现软件任务间的切换。要知道,中断并非总有的,主动弃权也不该总发生,总之,OS调度还得给本身留一手,在每一个Tick到来的时候,睁眼看看要不要作点啥。设计
好了,哥掏出个大盒子,打开一层又一层,如今,终于到最后火柴盒。如今,回到怎么解决系统挂起问题。对象
嵌入式系统OS通常都会提供TickAnnounce这样的接口或是钩子。没有也不要紧,直接挂Tick中断,不过别忘记在自定义的TickAnnounce里面调用原系统的TickAnnounce。TickAnnounce是OS任务调度睁眼后必作的,固然还作什么,就是TickAnnounce决定的了!接口
咱们要让TickAnnounce作什么呢?计数。
总共有三组数据须要统计:系统态计数,中断态计数,以及用户任务计数。准确点说,就是TickAnnounce每次运行的时候,先判断Tick发生时的模式,并将对应的计数+1。固然,每一个用户任务都是一个独立的计数,TickAnnounce直接取当前任务的TCB得到对应的计数器。嵌入式系统TCB老是开放给用户可见的,且里面总会提供几个用户自定义字段。咱们要作的,就是将其中一个用户自定义数据字段,做为咱们的计数器使用。
这里有两点须要注意:计数器是须要初始化和重置的,正常状况下,千万别在应用任务栈上对其进行修改,而应该是用一个简单的0/1开关通知TickAnnounce来完成;TickAnnounce里不能够出现任何打印,必要时能够有极少发生的msgq_send,计数器的读出,也应该尽可能由TickAnnounce写入特定的内存后,应用从对应内存块获取。队列
作完上面的工做,咱们就有了个CPU Utilization工具了。接着,咱们须要定义一个策略,让系统自动按期检测高负载任务或是中断处理。哥喜欢用过载门限来决定是否有异常,就是额外增长一个总TickAnnounce计数,在总TickAnnounce进入一个门限区间时,连续检查每次Tick计数对象,当达到过载门限时,TickAnnounce即记录当前模式及任务堆栈信息。跟coredump所不一样的是,不能只抓一次现场,而须要抓不少次。固然,还有处理超过统计区间后,从新开始统计,不然由于时间跨度变大后,峰值数据就不明显了!
这时候,咱们又要用SRAM了。嗯,SRAM真的是过重要了,哥作的不少嵌入式系统都离不开它!
为啥不能用RAM呢?TickAnnounce确定不能写flash,不解释,不懂的回头看上面。写内存是挺好的,但那样又有什么用呢,系统都挂起了,RAM里的内容,也无法看啊,最后只能是白忙活了!写SRAM就不同了,系统只有不掉电,总仍是在那,系统重启后,想怎么读出来都成。
哦,好像忘记说,抓n屡次现场后,记得触发CPU复位!固然,若是系统有狗,那就在被狗咬死前,尽量多的抓取现场信息。
后记:
1,SRAM老是颇有限的,才数K空间,记得这个和coredump不会同时发生,要重用那个空间;
2,堆栈完整信息,一次就能填满SRAM,这固然不行,抓取时,应该只关注顶部的数个函数调用,通常3~4个(一次现场大概16~20个字节)就足够勾画出程序调用关系了!
下次,要讲讲内存泄漏或是动态加载、动态不定等问题。