EDA365电子论坛网

标题: rt-thread系统 基于cortex-m3架构 的线程上下文切换实现 [打印本页]

作者: baqiao    时间: 2021-2-3 16:39
标题: rt-thread系统 基于cortex-m3架构 的线程上下文切换实现

. W" e5 [6 ]4 {3 I3 k3 A线程上下文切换等功能,一般采用汇编格式编写,不同cpu架构实现方式肯定不同,为了使rt-thread系统能够在不同的CPU架构上都能运行,RT-thread提供了一套libcpu抽象层来适配不同的cpu,现在我们重点来说libcpu中的rt_hw_context_switch函数和rt_hw_context_switch_interrupt函数在cortex-m3架构上的实现。
9 z  ]+ S: N- Y* c) \  @  g8 Q/ D2 |: A/ ~6 O$ x' @1 s
rt_hw_context_switch函数:在线程环境下,从当前线程切换到目标线程
" D  ~. D* x( e0 R9 q0 q$ [" N2 e3 j# K% y& Z' @
rt_hw_context_switch_interrupt 函数:在中断环境下,从当前线程切换到目标线程: r3 [; q* F* q$ W" n1 Y! L
* P/ j0 h  k+ z3 l  S
rt_hw_context_switch()函数,可以马上进行上下文切换,rt_hw_context_switch_interrupt 需要中断上下文函数执行完之后,才能进行上下文切换。
- f9 L% J: `% ~5 v4 B& A# q4 Z. t) S1 K, M1 L/ m/ [9 W1 n
在cortex-m3架构的cpu中,这两个函数的实现是相同的,因为,此架构的上下文切换功能都是基于PendSV中断实现的
7 M8 D0 \9 J. {6 w- K6 b
* y% ]/ }0 |  \) [% X% z( [cortex-m3架构  这两个函数的实现如下" |3 j* p$ p/ y
: ^- ^) e2 Q. a. }4 W
   
8 m0 }/ T8 D) x' Z" {2 \: C
7 G9 _; [1 n1 Y+ G3 @流程图如下:
) g+ E- {; H' I, y4 F" b6 I0 Q
$ h4 a7 q) ]  P, e & s9 l3 p, P$ f
! a9 a) l" _) Q: q9 Q

0 P: D, n( \6 L0 }( {4 \rt_thread_switch_interrupt_flag 变量是指示 上下文切换动作 是否在PendSV中断中执行过,如果等于1,表示需要切换,需要在PendSV中断中执行,也就是还没有执行,那么也就不需要再更新rt_interrupt_from_thread变量,(在上一次调用过rt_hw_context_switch/rt_hw_context_switch_interrupt 函数之后还没来得及切换线程,即rt_interrupt_from_thread变量保存的起始线程仍然有效,所以不需再保存),其他没有什么难以理解的点,直接看汇编代码的注释即可。
! x  u# P. l9 n  }  y
0 U  L+ W( q) W) G. {+ TPendSV_Handler实现(即Pend中断处理函数)/ h8 t0 r! g; G- w; @9 [8 t2 b$ ?+ Q
* y( Y8 b* [3 y0 ~! O5 G! @) w
7 H- l' ^: w4 e3 H/ f: W9 k

& R7 G  \$ D$ y+ W1 y5 w         注意,官网上以上代码段有一个地方注释有误   
: {) x+ N7 h( I! P4 n) [2 N! ?) G7 c; e
( O; E, \- J9 Z! m9 |8 g
" r" z5 y) |9 t
检查rt_interrupt_from_thread变量是为了在系统第一次调用上下文切换时,即调用rt_hw_context_switch_to函数(详见官网,这里没有写此函数),此时没有from线程,所以将rt_interrupt_from_thread变量设置为空。6 o" F; ?) v; M0 F( }5 R0 z

3 _) ^/ n/ Y4 s8 d, N4 q线程上下文切换是,上下文保存在各个线程的栈空间中, 这里我们只需要在PendSV中手动保存和恢复r4-r11寄存器,因为其它寄存器在中断发生和中断返回的时候会自动保存和自动恢复(r0-r3、r12、lr、pc和xpsr寄存器)。1 _; m) v6 R+ Q
$ m" M7 R3 n9 f5 _  u" ?
另外一个细节:rt_hw_context_switch 函数以及PendSV_Handler中断处理函数引入了一个全局变量rt_thread_switch_interrupt_flag ,主要的作用我用 以下场景说明:
  I0 U+ o8 o" ?3 K# k
$ {/ s5 E- I# H7 D5 Nrt_hw_context_switch 函数准备好from线程的数据后(此时rt_hw_context_switch函数可能运行在用户级线程中,也可能运行在中断处理函数中,特别是实时时钟的中断处理函数中),还没来得及触发PendSV中断,就被其他中断打断,在其他中断中又调用了rt_hw_context_switch 函数进行线程切换,这时候就不需要重新准备from线程数据,只需要准备to线程数据,并悬起PendSV中断,然后中断处理函数返回
- ?7 ^; e1 i7 K3 y5 L4 h2 M此时如果之前的rt_hw_context_switch 如果运行在用户级线程模式,则先不返回rt_hw_context_switch 函数,而是响应之前悬起的PendSV中断,PendSV中断被触发,完成线程切换后再返回rt_hw_context_switch 函数,rt_hw_context_switch函数接着运行,在准备好to线程后,又一次悬起了PendSV中断,PendSV中断之后又被触发,但是此时不会再执行线程切换了,因为rt_thread_switch_interrupt_flag 全局变量已经在上一次PendSV中断处理函数执行中被清零,PendSV中断服务函数将直接退出,避免无效且错误的线程切换。5 g( B0 O# J; l) X$ |  f' _; x3 S

+ b) D7 {1 b% c4 U3 _+ f这就是rt_thread_switch_interrupt_flag全局变量的一个应用场景,但是我观察rtthread系统的代码发现,rt_hw_context_switch函数都是在rt_schedule()函数中调用的,而rt_schedule()函数会在调用rt_hw_context_switch 函数之前关闭全局中断,所以上述我说的场景并不会发生,rt_hw_context_switch函数执行一半的时候并不会被打断,所以实际上rt_thread_switch_interrupt_flag并没有发挥作用,但是实现的时候,还是加入了上述机制,注意,以上分析只是个人观点,完全有可能是错的。0 [: O3 S5 _$ Q3 h7 R

作者: ExxNEN    时间: 2021-2-3 17:15
rt-thread系统 基于cortex-m3架构 的线程上下文切换实现




欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/) Powered by Discuz! X3.2