[bf54252] | 1 | /** |
---|
| 2 | * @file |
---|
| 3 | * |
---|
| 4 | * @brief Dispatch Thread |
---|
| 5 | * @ingroup ScoreThread |
---|
| 6 | */ |
---|
| 7 | |
---|
[05df0a8] | 8 | /* |
---|
[dca9a82] | 9 | * COPYRIGHT (c) 1989-2009. |
---|
[05df0a8] | 10 | * On-Line Applications Research Corporation (OAR). |
---|
| 11 | * |
---|
| 12 | * The license and distribution terms for this file may be |
---|
[dcf3687] | 13 | * found in the file LICENSE in this distribution or at |
---|
[dd687d97] | 14 | * http://www.rtems.com/license/LICENSE. |
---|
[05df0a8] | 15 | */ |
---|
| 16 | |
---|
[a8eed23] | 17 | #if HAVE_CONFIG_H |
---|
| 18 | #include "config.h" |
---|
| 19 | #endif |
---|
| 20 | |
---|
[05df0a8] | 21 | #include <rtems/system.h> |
---|
| 22 | #include <rtems/score/apiext.h> |
---|
| 23 | #include <rtems/score/context.h> |
---|
| 24 | #include <rtems/score/interr.h> |
---|
| 25 | #include <rtems/score/isr.h> |
---|
| 26 | #include <rtems/score/object.h> |
---|
| 27 | #include <rtems/score/priority.h> |
---|
| 28 | #include <rtems/score/states.h> |
---|
| 29 | #include <rtems/score/sysstate.h> |
---|
| 30 | #include <rtems/score/thread.h> |
---|
[4fc370e] | 31 | #include <rtems/score/threaddispatch.h> |
---|
[05df0a8] | 32 | #include <rtems/score/threadq.h> |
---|
[3be0c9a] | 33 | #include <rtems/score/userextimpl.h> |
---|
[05df0a8] | 34 | #include <rtems/score/wkspace.h> |
---|
| 35 | |
---|
[c6f7e060] | 36 | #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__ |
---|
[c16bcc0] | 37 | #include <rtems/score/timestamp.h> |
---|
[c3330a8] | 38 | #endif |
---|
| 39 | |
---|
[d4dc7c8] | 40 | #if defined(RTEMS_SMP) |
---|
| 41 | #include <rtems/score/smp.h> |
---|
| 42 | #endif |
---|
| 43 | |
---|
[05df0a8] | 44 | void _Thread_Dispatch( void ) |
---|
| 45 | { |
---|
| 46 | Thread_Control *executing; |
---|
| 47 | Thread_Control *heir; |
---|
| 48 | ISR_Level level; |
---|
| 49 | |
---|
[d4dc7c8] | 50 | #if defined(RTEMS_SMP) |
---|
[9b83a66] | 51 | /* |
---|
| 52 | * WARNING: The SMP sequence has severe defects regarding the real-time |
---|
| 53 | * performance. |
---|
| 54 | * |
---|
| 55 | * Consider the following scenario. We have three tasks L (lowest |
---|
| 56 | * priority), M (middle priority), and H (highest priority). Now let a |
---|
| 57 | * thread dispatch from M to L happen. An interrupt occurs in |
---|
| 58 | * _Thread_Dispatch() here: |
---|
| 59 | * |
---|
| 60 | * void _Thread_Dispatch( void ) |
---|
| 61 | * { |
---|
| 62 | * [...] |
---|
| 63 | * |
---|
| 64 | * post_switch: |
---|
| 65 | * |
---|
| 66 | * _ISR_Enable( level ); |
---|
| 67 | * |
---|
| 68 | * <-- INTERRUPT |
---|
| 69 | * <-- AFTER INTERRUPT |
---|
| 70 | * |
---|
| 71 | * _Thread_Unnest_dispatch(); |
---|
| 72 | * |
---|
[04b5d17] | 73 | * _API_extensions_Run_post_switch(); |
---|
[9b83a66] | 74 | * } |
---|
| 75 | * |
---|
| 76 | * The interrupt event makes task H ready. The interrupt code will see |
---|
| 77 | * _Thread_Dispatch_disable_level > 0 and thus doesn't perform a |
---|
| 78 | * _Thread_Dispatch(). Now we return to position "AFTER INTERRUPT". This |
---|
| 79 | * means task L executes now although task H is ready! Task H will execute |
---|
| 80 | * once someone calls _Thread_Dispatch(). |
---|
| 81 | */ |
---|
| 82 | _Thread_Disable_dispatch(); |
---|
| 83 | |
---|
[d4dc7c8] | 84 | /* |
---|
| 85 | * If necessary, send dispatch request to other cores. |
---|
| 86 | */ |
---|
| 87 | _SMP_Request_other_cores_to_dispatch(); |
---|
| 88 | #endif |
---|
| 89 | |
---|
| 90 | /* |
---|
| 91 | * Now determine if we need to perform a dispatch on the current CPU. |
---|
| 92 | */ |
---|
[05df0a8] | 93 | executing = _Thread_Executing; |
---|
| 94 | _ISR_Disable( level ); |
---|
[4b1d261] | 95 | while ( _Thread_Dispatch_necessary == true ) { |
---|
[05df0a8] | 96 | heir = _Thread_Heir; |
---|
[a936aa49] | 97 | #if defined(RTEMS_SMP) |
---|
| 98 | executing->is_executing = false; |
---|
| 99 | heir->is_executing = true; |
---|
| 100 | #else |
---|
[9b83a66] | 101 | _Thread_Dispatch_set_disable_level( 1 ); |
---|
| 102 | #endif |
---|
[4b1d261] | 103 | _Thread_Dispatch_necessary = false; |
---|
[05df0a8] | 104 | _Thread_Executing = heir; |
---|
[11e8bc5] | 105 | |
---|
| 106 | /* |
---|
| 107 | * When the heir and executing are the same, then we are being |
---|
| 108 | * requested to do the post switch dispatching. This is normally |
---|
| 109 | * done to dispatch signals. |
---|
| 110 | */ |
---|
| 111 | if ( heir == executing ) |
---|
| 112 | goto post_switch; |
---|
| 113 | |
---|
| 114 | /* |
---|
| 115 | * Since heir and executing are not the same, we need to do a real |
---|
| 116 | * context switch. |
---|
| 117 | */ |
---|
[81b329a] | 118 | #if __RTEMS_ADA__ |
---|
[05df0a8] | 119 | executing->rtems_ada_self = rtems_ada_self; |
---|
| 120 | rtems_ada_self = heir->rtems_ada_self; |
---|
[81b329a] | 121 | #endif |
---|
[e9f6d10] | 122 | if ( heir->budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE ) |
---|
| 123 | heir->cpu_time_budget = _Thread_Ticks_per_timeslice; |
---|
[11e8bc5] | 124 | |
---|
[05df0a8] | 125 | _ISR_Enable( level ); |
---|
| 126 | |
---|
[c6f7e060] | 127 | #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__ |
---|
[c3330a8] | 128 | { |
---|
[c16bcc0] | 129 | Timestamp_Control uptime, ran; |
---|
[c3330a8] | 130 | _TOD_Get_uptime( &uptime ); |
---|
[c16bcc0] | 131 | _Timestamp_Subtract( |
---|
| 132 | &_Thread_Time_of_last_context_switch, |
---|
| 133 | &uptime, |
---|
| 134 | &ran |
---|
| 135 | ); |
---|
| 136 | _Timestamp_Add_to( &executing->cpu_time_used, &ran ); |
---|
[c3330a8] | 137 | _Thread_Time_of_last_context_switch = uptime; |
---|
| 138 | } |
---|
| 139 | #else |
---|
[d4dc7c8] | 140 | { |
---|
[8896c97] | 141 | _TOD_Get_uptime( &_Thread_Time_of_last_context_switch ); |
---|
[d4dc7c8] | 142 | heir->cpu_time_used++; |
---|
| 143 | } |
---|
[c3330a8] | 144 | #endif |
---|
[05df0a8] | 145 | |
---|
[0df8293e] | 146 | /* |
---|
| 147 | * Switch libc's task specific data. |
---|
| 148 | */ |
---|
| 149 | if ( _Thread_libc_reent ) { |
---|
| 150 | executing->libc_reent = *_Thread_libc_reent; |
---|
| 151 | *_Thread_libc_reent = heir->libc_reent; |
---|
| 152 | } |
---|
| 153 | |
---|
[05df0a8] | 154 | _User_extensions_Thread_switch( executing, heir ); |
---|
| 155 | |
---|
| 156 | /* |
---|
| 157 | * If the CPU has hardware floating point, then we must address saving |
---|
| 158 | * and restoring it as part of the context switch. |
---|
| 159 | * |
---|
| 160 | * The second conditional compilation section selects the algorithm used |
---|
| 161 | * to context switch between floating point tasks. The deferred algorithm |
---|
| 162 | * can be significantly better in a system with few floating point tasks |
---|
| 163 | * because it reduces the total number of save and restore FP context |
---|
| 164 | * operations. However, this algorithm can not be used on all CPUs due |
---|
| 165 | * to unpredictable use of FP registers by some compilers for integer |
---|
| 166 | * operations. |
---|
| 167 | */ |
---|
| 168 | |
---|
[48f89683] | 169 | #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) |
---|
| 170 | #if ( CPU_USE_DEFERRED_FP_SWITCH != TRUE ) |
---|
| 171 | if ( executing->fp_context != NULL ) |
---|
| 172 | _Context_Save_fp( &executing->fp_context ); |
---|
| 173 | #endif |
---|
| 174 | #endif |
---|
| 175 | |
---|
| 176 | _Context_Switch( &executing->Registers, &heir->Registers ); |
---|
| 177 | |
---|
[ca7858bb] | 178 | #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) |
---|
[05df0a8] | 179 | #if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE ) |
---|
[63f786e] | 180 | if ( (executing->fp_context != NULL) && |
---|
| 181 | !_Thread_Is_allocated_fp( executing ) ) { |
---|
[05df0a8] | 182 | if ( _Thread_Allocated_fp != NULL ) |
---|
| 183 | _Context_Save_fp( &_Thread_Allocated_fp->fp_context ); |
---|
[48f89683] | 184 | _Context_Restore_fp( &executing->fp_context ); |
---|
| 185 | _Thread_Allocated_fp = executing; |
---|
[05df0a8] | 186 | } |
---|
| 187 | #else |
---|
| 188 | if ( executing->fp_context != NULL ) |
---|
[48f89683] | 189 | _Context_Restore_fp( &executing->fp_context ); |
---|
[05df0a8] | 190 | #endif |
---|
| 191 | #endif |
---|
| 192 | |
---|
| 193 | executing = _Thread_Executing; |
---|
| 194 | |
---|
| 195 | _ISR_Disable( level ); |
---|
| 196 | } |
---|
| 197 | |
---|
[11e8bc5] | 198 | post_switch: |
---|
[9b83a66] | 199 | #ifndef RTEMS_SMP |
---|
| 200 | _Thread_Dispatch_set_disable_level( 0 ); |
---|
| 201 | #endif |
---|
[05df0a8] | 202 | |
---|
| 203 | _ISR_Enable( level ); |
---|
| 204 | |
---|
[9b83a66] | 205 | #ifdef RTEMS_SMP |
---|
| 206 | _Thread_Unnest_dispatch(); |
---|
| 207 | #endif |
---|
| 208 | |
---|
[04b5d17] | 209 | _API_extensions_Run_post_switch( executing ); |
---|
[05df0a8] | 210 | } |
---|