阅读《RT-Thread内核实现与应用开发实战指南》阅读 rt_hw_context_switch函数源码时对其中的rt_thread_switch_interrupt_flag 的用途不是很理解,代码如下:
- rt_hw_context_switch_interrupt:
- rt_hw_context_switch:
- /* set rt_thread_switch_interrupt_flag to 1 */
- LDR r2, =rt_thread_switch_interrupt_flag
- LDR r3, [r2]
- CMP r3, #1
- BEQ _reswitch
- MOV r3, #1
- STR r3, [r2]
- LDR r2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */
- STR r0, [r2]
- _reswitch:
- LDR r2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */
- STR r1, [r2]
- LDR r0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
- LDR r1, =NVIC_PENDSVSET
- STR r1, [r0]
- BX LR
[color=rgb(51, 102, 153) !important]复制代码
上述汇编代码等同如下的C代码:
- void rt_hw_context_switch_interrupt(rt_uint32_t from, rt_uint32_t to)
- {
- if (rt_thread_switch_interrupt_flag != 1)
- {
- rt_thread_switch_interrupt_flag = 1;
- rt_interrupt_from_thread = from;
- }
- rt_interrupt_to_thread = to;
- }
[color=rgb(51, 102, 153) !important]复制代码
rt_thread_switch_interrupt_flag != 1时更新线程切换的form线程,否则不更新。rt_thread_switch_interrupt_flag值会在PendSV_Handler中清零,rt_hw_context_switch_interrupt中置1,初始状态为0。
- /* r0 --> switch from thread stack
- * r1 --> switch to thread stack
- * psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
- */
- .global PendSV_Handler
- .type PendSV_Handler, %function
- PendSV_Handler:
- /* disable interrupt to protect context switch */
- MRS r2, PRIMASK
- CPSID I
- /* get rt_thread_switch_interrupt_flag */
- LDR r0, =rt_thread_switch_interrupt_flag
- LDR r1, [r0]
- CBZ r1, pendsv_exit /* pendsv already handled */
- /* clear rt_thread_switch_interrupt_flag to 0 */
- MOV r1, #0x00
- STR r1, [r0]
- LDR r0, =rt_interrupt_from_thread
- LDR r1, [r0]
- CBZ r1, switch_to_thread /* skip register save at the first time */
- MRS r1, psp /* get from thread stack pointer */
- #if defined (__VFP_FP__) && !defined(__SOFTFP__)
- TST lr, #0x10 /* if(!EXC_RETURN[4]) */
- VSTMDBEQ r1!, {d8 - d15} /* push FPU register s16~s31 */
- #endif
- STMFD r1!, {r4 - r11} /* push r4 - r11 register */
- #if defined (__VFP_FP__) && !defined(__SOFTFP__)
- MOV r4, #0x00 /* flag = 0 */
- TST lr, #0x10 /* if(!EXC_RETURN[4]) */
- MOVEQ r4, #0x01 /* flag = 1 */
- STMFD r1!, {r4} /* push flag */
- #endif
- LDR r0, [r0]
- STR r1, [r0] /* update from thread stack pointer */
- switch_to_thread:
- LDR r1, =rt_interrupt_to_thread
- LDR r1, [r1]
- LDR r1, [r1] /* load thread stack pointer */
- #if defined (__VFP_FP__) && !defined(__SOFTFP__)
- LDMFD r1!, {r3} /* pop flag */
- #endif
- LDMFD r1!, {r4 - r11} /* pop r4 - r11 register */
- #if defined (__VFP_FP__) && !defined(__SOFTFP__)
- CMP r3, #0 /* if(flag_r3 != 0) */
- VLDMIANE r1!, {d8 - d15} /* pop FPU register s16~s31 */
- #endif
- MSR psp, r1 /* update stack pointer */
- #if defined (__VFP_FP__) && !defined(__SOFTFP__)
- ORR lr, lr, #0x10 /* lr |= (1 << 4), clean FPCA. */
- CMP r3, #0 /* if(flag_r3 != 0) */
- BICNE lr, lr, #0x10 /* lr &= ~(1 << 4), set FPCA. */
- #endif
- pendsv_exit:
- /* restore interrupt */
- MSR PRIMASK, r2
- ORR lr, lr, #0x04
- BX lr
[color=rgb(51, 102, 153) !important]复制代码
按照正常的函数调用流程,schedule -》 rt_hw_context_switch -》PendSV_Handler rt_thread_switch_interrupt_flag值应该都为0,除非在rt_hw_context_switch 和 PendSV_Handler 之间再次调用rt_hw_context_switch rt_thread_switch_interrupt_flag值会为1。
在网上找到了想要的答案:
只要是“硬件”入栈 PendSV,那么就说明有 schedule 发生了,这时候被换出的线程被保存在了 from_thread 那个变量里,to_thread 变量存储的是要换进来的线程,并且 flag = 1。如果在硬件入栈的时候发生中断,那么, cortex-m3 会在入栈之后执行高优先级的中断(必然不是 PendSV),而挂起 PendSV。假设在此中断例程中调用了 schedule,那么它看到 flag == 1 了,就不会再去保存旧的线程地址到 from_thread 了,原因很简单,旧的线程始终没变~然后 PendSV 里对 flag 做的跳转保证了 PendSV 只执行一次。
rt_thread_switch_interrupt_flag 标志的作用就是,前一次PendSV_Handler 被打断的情况下,再次进行线程上下文切换的话,不更新rt_interrupt_from_thread线程相关的内容,只更新rt_interrupt_to_thread线程线程内容。
在网上找到了这个问题的资料,链接如下(可能需要梯子),访问不了的话可以参见附件:
https://groups.google.com/forum/#!msg/rt-thread-cnusers/v_MDGup3G8Q/gxq8J6QUVX0J本文转载于【RT-Thread内核实现与应用开发实战指南】读书笔记三
http://www.stmcu.org.cn/module/forum/thread-618966-1-1.html
|
共1人点赞
|