首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

上下文切换(3)

上下文切换(3)

下面是

;函数原型: void__asm_start_thread(struct thread_vm  *new_vm);

;-----------------------------------------------------------------------------

__asm_start_threadPROC

   EXPORT __asm_start_thread

   mov    r1,#2

   msr    control,r1         ;切换到特权线程模式,栈指针用psp

   ldr    sp,[r0]            ;取得新上下文指针

   bl     int_restore_asyn_signal ;对应done函数开头的 int_save_asyn_signal 调用

   svc    0                  ;切入新上下文

      ENDP

4、切入线程

__asm_turnto_context函数不保存当前线程的上下文,直接把新线程的上下文恢复到cpu中。当一条事件处理完毕,该事件的线程可能被销毁,这种情况下,就无需保存当前线程的上下文,直接切入新线程的上下文即可。__asm_turnto_context函数只做一件事:调用svc0恢复新线程上下文:

;函数原型: void__asm_turnto_context(struct thread_vm  *new_vm);

;-----------------------------------------------------------------------------
__asm_turnto_contextPROC
   EXPORT  __asm_turnto_context
   ldr    sp,[r0]            ;取得新上下文指针
   bl     int_restore_asyn_signal ;对应done函数开头的 int_save_asyn_signal 调用
   svc    0                  ;切入新上下文
      ENDP
5、复位旧线程,切入新线程

当一条事件处理完成如果系统调度发现该事件的线程应该予以保留就调用__asm_reset_switch复位该线程,然后切入新的最高优先级的就绪线程。__asm_reset_switch函数是__asm_reset_thread__asm_turnto_context的结合体。代码如下:
;函数原型:void__asm_reset_switch(void (*thread_routine)(struct event_script*),
;                          struct  thread_vm *new_vm,struct thread_vm *old_vm);
;-----------------------------------------------------------------------------
__asm_reset_switchPROC
   EXPORT  __asm_reset_switch
   ldr    sp,[r2,#4]         ;取老虚拟机栈顶指针

   mov    r12,#0x01000000     ;xpsr的初始值

   ldr    r11,=__djy_vm_engine   ;取虚拟机引擎指针

   push   {r11,r12}          ;pc,xpsr

   sub    sp,sp,#14*4        ;后退14个寄存器,初始状态r0-r12中,除r0外均无意义,

                               ;__vm_engine函数不返回,lr也无意义

                               ;至此,完成老虚拟机复位

   str    r0,[sp,#8*4]       ;保存 thread_routine指针.至此,完成老线程重置

   str    sp,[r2]            ;保存当前栈指针到old_vm->stack



   ldr    sp,[r1]            ;取得新上下文指针

   bl     int_restore_asyn_signal ;对应done函数开头的 int_save_asyn_signal 调用

   svc    0                  ;切入新上下文

      ENDP

6、中断服务例程中的上下文切换

最后一级异步信号(包括systick,由于djyos forcm3把所有异步信号优先级设为相同,故不会嵌套)返回前,即将返回线程模式时,系统将检查在中断服务例程的执行过程中是否有更高优先级的事件(线程)就绪。如果有,则调用__asm_switch_context_int函数执行上下文切换,该函数完成2个操作:
a、把当前PSP保存在被ISR中断的线程虚拟机的线程控制块中。
b、从高优先级的事件的线程控制块中取出SP,放到PSP寄存器中。
函数代码如下:
;函数原型: void__asm_switch_context_int(struct thread_vm *new_vm,struct thread_vm*old_vm);
;-----------------------------------------------------------------------------
__asm_switch_context_int   PROC
   EXPORT __asm_switch_context_int
   mrs    r2,psp     ;取被中断线程的psp
   str    r2,[r1]      ;psp写入虚拟机数据结构中
   ldr    r2,[r0]      ;取待切入线程的psp
   msr    psp,r2     ;待切入线程的当前栈指针写入psp,中断返回恢复上下文将以此为准
   bx     lr
      ENDP
7、一点小经验

cm3中从异常返回必须用bxlr,不能用mov pc,lr,否则会发生存储器管理fault(取址违例)
读函数名得到奇数地址。
中断压栈的PC是偶数地址。
中断返回时,无论栈中的PC值是奇数还是偶数,都能正确返回。
继承事业,薪火相传
返回列表