_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