_Thread_Dispatch_disable_level 这个变量不为0时表示线程的调度被禁止。为1表示被禁止了一次,为N表示调度被嵌套禁止了(N-1)次。
_Context_Switch_necessary变量不为0表示需要进行上下文切换。
一般操作系统调度线程时,必须在以下的几种情况下发生:
1.正在运行的线程被阻塞(这种情况比较多,请参考 rtesm C user.pdf中的 task 一章);
2.线程被中断,中断执行完毕后有一个更高优先级别的任务就绪;
3.使用时间片轮转调度,当前任务的时间片用完了,有其他的同优先级别的任务就绪。
对于1和3这种情况,直接调用上下文切换的代码就可以实现线程切换。这个是由 _Context_Switch() 函数实现。不同的处理器上是不一样的。需要自己去撰写,一般都是汇编语言实现。
对于2,这种情况就相对比较复杂了。RTEMS 为了快速响应中断,并从中断中快速返回。
或者发生中断嵌套了,必须正确的知道嵌套深度,并在合适的位置进行上下文切换。
以ARM为例,/cpukit/score/cpu/arm/cpu_asm.S,中存放着进入异常的代码。
但是并未对这些情况做处理,只是简单的进入中断异常而已。
中断异常的处理代码必须自己用汇编语言撰写。
ARM的中断异常在:/c/src/lib/libbsp/arm/shared/irq/irq_asm.S中。
会看到对_ISR_Nest_level、_Thread_Dispatch_disable_level、_Context_Switch_necessary这三个变量的操作。
代码本身没有什么难度,主要理解RTEMS中断的处理流程和ARM的工作流程。您可以自己学习,我会在博客中写出这些代码的分析。
您也可以找我讨论,谢谢。
抱歉,我没有将这个解释透彻。你的理解一部分是正确的,另外一部分缺少了一些细节。
同优先级的多个任务,时间片轮转调度方式下,当某个任务的时间片用完后,操作系统会自动运行同优先级的其它任务.当前任务
是不需要发出调度相关的信息.当时间中断到达后,调用rtems_clock_tick--> _Thread_Tickle_timeslice --> _Thread_Reset_timeslice 在这里当前任务会被放到任务队列的末尾,最高优先级任务更改为队列中的第一个任务,上下文切换为TRUE,有必要进行任务切换.
这部分 理解是正确的。但后面的部分就有偏差了。
首先,RTEMS来了一个tick后,操作系统就会对进行一些操作,其中包括将每个时间片减1,直到它为0。这部分代码您可以在 cpukit/rtems/src/clocktick.c中找到。在这里我们必须明白,rtems_status_code rtems_clock_tick( void )这个函数是在中断中执行的。不是用户手工调用的。
中断这块代码我不知道您仔细阅读了没有,这块有比较多的细节内容。我将
rtems 4.9.4 ARM 的 /c/src/lib/libbsp/arm/shared/irq/irq_asm.S 这部分画成活动图
(画得不好,一些和处理器高度相关的操作我省去了,你凑合着看)。
假设时间片的最后一个节拍到了,调用ExecuteITHandler后,即执行了rtems_status_code rtems_clock_tick( void )函数。您在根据这个图看看,是不是要进行调度了?这部分代码的流程比较多,但代码本身没有难度,阅读时应抓大放小。
呵呵,要我怎么说呢?你说的这种情况是不存在的。系统的确是通过_Thread_Dispatch这个函数实现的。但_Thread_Dispatch_disable_level的初始值在多线程开始后,进入第一个运行的线程时清0,否则操作系统是无法调度的。
RTEMS 的操作系统比较特殊,和uC/OS-II不可同日而语。每个线程的入口不是你定义的函数,而是_Thread_Handler函数,
其中就有:
/*
* At this point, the dispatch disable level BETTER be 1.
*/
_Thread_Enable_dispatch();
这时已经将_Thread_Enable_dispatch_level改为了0,以允许调度。
注意到你说的:在调试的过程中也验证了这点. 呵呵,是用printf/printk还是单步调试? 如果使用printf/printk,
那么你的打印位置有问题;如果单步执行的话……总之,RTEMS的代码本身难度不大,主要是流程复杂,要在理解流程的前提下,看代码。不然很痛苦。