_Thread_Dispatch() 函数源码注解(RTEMS)

 _Thread_Dispatch()函数源码注解

处理器平台:S3C2440A  ARM9

操作系统:RTEMS-4.10.2

源文件目录:RTEMS-4.10.2/cpukit/score/src/Threaddispatch.c

说明:

      在每次需要切换任务时,均会调用_Thread_Dispatch()函数执行任务切换,比如:

      1.  arm_exc_interrupts 汇编函数,在执行完中断服务程序ISR后,如果需要切换任务,则会调用此函数;

      2.  _Thread_Enable_Dispatch()函数,在每次使能任务切换时,如果需要切换任务,则会调用此函数;

      3.  rtems_clock_tick()函数,在每一个系统滴哒,如果需要切换任务,则会调用此函数,等等。

下面即介绍该函数的执行流程:

  1 void _Thread_Dispatch( void )
  2 {
  3     Thread_Control   *executing;
  4     Thread_Control   *heir;
  5     ISR_Level         level;
  6 
  7     executing   = _Thread_Executing;                                       /* 读取当前执行任务的指针 */
  8     _ISR_Disable( level );                                                 /* 禁止中断 */
  9     while ( _Context_Switch_necessary == true )                            /* 只有在_Context_Switch_necessary=true的情况下才执行,而且是while循环 */ 
 10     {
 11         heir = _Thread_Heir;
 12         _Thread_Dispatch_disable_level = 1;                                /* 禁止任务调度,等下使能中断后,就不会发生任务切换了 */
 13         _Context_Switch_necessary = false;                                 /* _Context_Switch_necessary = 0,清零 */
 14         _Thread_Executing = heir;
 15 
 16         #if __RTEMS_ADA__
 17         executing->rtems_ada_self = rtems_ada_self;
 18         rtems_ada_self = heir->rtems_ada_self;
 19         #endif
 20 
 21         if ( heir->budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE )    /* 如果定义了任务切换时复位时间片 */
 22             heir->cpu_time_budget = _Thread_Ticks_per_timeslice;           /* 将时间片设置成默认值,当多个任务同优先级运行时,将会按时间片分时执行 */
 23         _ISR_Enable( level );                                              /* 使能中断 */
 24 
 25         #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__                         /* 1. 计算从上一次任务切换到此次任务切换中间,任务运行了多长时间 */
 26         {                                                                  /* 2. 同时也计算任务总共运行了多长时间 */
 27             Timestamp_Control uptime, ran;
 28             _TOD_Get_uptime( &uptime );                                    /* 获取系统的启动时间 uptime */
 29             _Timestamp_Subtract(                                           /* ran = uptime - _Thread_Time_of_last_context_switch */
 30               &_Thread_Time_of_last_context_switch,
31 &uptime, 32 &ran ); /* 从上一次任务切换至本次任务切换,任务运行了多长时间 */ 33 _Timestamp_Add_to( &executing->cpu_time_used, &ran ); /* 累加计算任务总共运行时长 cpu_time_used += ran */ 34 _Thread_Time_of_last_context_switch = uptime; /* 更新上一次任务切换时间 _Thread_Time_of_last_context_switch */ 35 } 36 #else 37 heir->cpu_time_used++; 38 #endif 39 40 /* 41 * Switch libc's task specific data. 42 */ 43 if ( _Thread_libc_reent ) 44 { 45 executing->libc_reent = *_Thread_libc_reent; 46 *_Thread_libc_reent = heir->libc_reent; 47 } 48 49 _User_extensions_Thread_switch( executing, heir ); 50 51 /* 52 * If the CPU has hardware floating point, then we must address saving 53 * and restoring it as part of the context switch. 54 * 55 * The second conditional compilation section selects the algorithm used 56 * to context switch between floating point tasks. The deferred algorithm 57 * can be significantly better in a system with few floating point tasks 58 * because it reduces the total number of save and restore FP context 59 * operations. However, this algorithm can not be used on all CPUs due 60 * to unpredictable use of FP registers by some compilers for integer 61 * operations. 62 */ 63 64 #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) 65 #if ( CPU_USE_DEFERRED_FP_SWITCH != TRUE ) 66 if ( executing->fp_context != NULL ) 67 _Context_Save_fp( &executing->fp_context ); 68 #endif 69 #endif 70 71 _Context_Switch( &executing->Registers, &heir->Registers ); /* Context Switch,上下文切换,该函数见下面单独介绍 */ 72 73 #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) /* 保护和恢复浮点上下文 */ 74 #if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE ) 75 if ( (executing->fp_context != NULL) && 76 !_Thread_Is_allocated_fp( executing ) ) 77 { 78 if ( _Thread_Allocated_fp != NULL ) 79 _Context_Save_fp( &_Thread_Allocated_fp->fp_context ); 80 _Context_Restore_fp( &executing->fp_context ); 81 _Thread_Allocated_fp = executing; 82 } 83 #else 84 if ( executing->fp_context != NULL ) 85 _Context_Restore_fp( &executing->fp_context ); 86 #endif 87 #endif 88 89 executing = _Thread_Executing; /* executing 指向即将执行的任务 */ 90 91 _ISR_Disable( level ); 92 } 93 94 _Thread_Dispatch_disable_level = 0; 95 96 _ISR_Enable( level ); 97 98 if ( _Thread_Do_post_task_switch_extension || 99 executing->do_post_task_switch_extension ) /* 如果即将执行的任务接收到了异步信号,则处理该异步信号 */ 100 { 101 executing->do_post_task_switch_extension = false; 102 _API_extensions_Run_postswitch(); 103 } 104 105 }

 

 

_CPU_Context_switch 上下文切换函数

源文件目录:RTEMS-4.10.2/cpukit/score/cpu/arm/cpu_asm.s

函数说明:

1.  该函数是一个汇编函数,它的C函数原型为:_Context_Switch(_executing,_heir),即上面函数的第71行;

2.  根据APCS标准:R0存储第一个参数,即 &executing->Registers;R1存储第二个参数,即 &heir->Registers;

3.  该函数将当前的上下文存入 &executing->Registers 中,再将 &heir->Registers 中内容恢复到上下文,完成任务的切换;

4.  根据 APCS 标准,R0~R3用于参数传递,不属于调用者的上下文,所以不需要保存,因此上下文为:R4,R5,R6,R7,R8,R9,R10,R11,R12,R13(SP),R14(LR),CPSR;

 1 DEFINE_FUNCTION_ARM(_CPU_Context_switch)
 2 /* Start saving context | 保存上下文 */
 3     mrs    r2, cpsr                                                       /* R2 <- CPSR */
 4     stmia    r0,  {r2, r4, r5, r6, r7, r8, r9, r10, r11, r13, r14}        /* Context: R4,R5,R6,R7,R8,R9,R10,R11,R12,R13(SP),R14(LR),CPSR */
 5 
 6 
 7 /* Start restoring context | 恢复上下文 */
 8 _restore:
 9     ldmia    r1,  {r2, r4, r5, r6, r7, r8, r9, r10, r11, r13, r14}10     msr    cpsr, r2
11 #ifdef __thumb__
12     bx    lr
13     nop
14 #else
15     mov    pc, lr                                                         /* 返回到 LR 处执行,因为指令不带 s 标志,因此不会将SPSR寄存器的值恢复到CPSR中 */
16 #endif

 

posted @ 2015-12-13 10:25  zhousm  阅读(811)  评论(0编辑  收藏  举报