打印
[应用相关]

实验分享【RT-Thread内核实现与应用开发实战指南】读书笔...

[复制链接]
482|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
年轻的国王|  楼主 | 2020-8-6 22:08 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
阅读《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


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:每天都要开心呀

210

主题

505

帖子

4

粉丝