[f7f1d77] | 1 | /** |
---|
| 2 | * @file |
---|
[05df0a8] | 3 | * |
---|
[f7f1d77] | 4 | * @brief Restart Thread |
---|
| 5 | * @ingroup ScoreThread |
---|
| 6 | */ |
---|
| 7 | |
---|
| 8 | /* |
---|
[08311cc3] | 9 | * COPYRIGHT (c) 1989-1999. |
---|
[05df0a8] | 10 | * On-Line Applications Research Corporation (OAR). |
---|
| 11 | * |
---|
[9949d8a7] | 12 | * Copyright (c) 2014, 2016 embedded brains GmbH. |
---|
[1b1be254] | 13 | * |
---|
[05df0a8] | 14 | * The license and distribution terms for this file may be |
---|
[dcf3687] | 15 | * found in the file LICENSE in this distribution or at |
---|
[c499856] | 16 | * http://www.rtems.org/license/LICENSE. |
---|
[05df0a8] | 17 | */ |
---|
| 18 | |
---|
[a8eed23] | 19 | #if HAVE_CONFIG_H |
---|
| 20 | #include "config.h" |
---|
| 21 | #endif |
---|
| 22 | |
---|
[5618c37a] | 23 | #include <rtems/score/threadimpl.h> |
---|
[1b1be254] | 24 | #include <rtems/score/apimutex.h> |
---|
| 25 | #include <rtems/score/assert.h> |
---|
| 26 | #include <rtems/score/chainimpl.h> |
---|
| 27 | #include <rtems/score/isrlock.h> |
---|
| 28 | #include <rtems/score/schedulerimpl.h> |
---|
| 29 | #include <rtems/score/sysstate.h> |
---|
[dcd5e26] | 30 | #include <rtems/score/threadqimpl.h> |
---|
[3be0c9a] | 31 | #include <rtems/score/userextimpl.h> |
---|
[dcd5e26] | 32 | #include <rtems/score/watchdogimpl.h> |
---|
[1b1be254] | 33 | #include <rtems/score/wkspace.h> |
---|
| 34 | |
---|
[232147dd] | 35 | #define THREAD_JOIN_TQ_OPERATIONS &_Thread_queue_Operations_priority |
---|
| 36 | |
---|
[6e4f929] | 37 | static void _Thread_Life_action_handler( |
---|
| 38 | Thread_Control *executing, |
---|
| 39 | Thread_Action *action, |
---|
| 40 | ISR_lock_Context *lock_context |
---|
| 41 | ); |
---|
| 42 | |
---|
[1b1be254] | 43 | typedef struct { |
---|
| 44 | Chain_Control Chain; |
---|
| 45 | ISR_lock_Control Lock; |
---|
| 46 | } Thread_Zombie_control; |
---|
| 47 | |
---|
| 48 | static Thread_Zombie_control _Thread_Zombies = { |
---|
| 49 | .Chain = CHAIN_INITIALIZER_EMPTY( _Thread_Zombies.Chain ), |
---|
| 50 | .Lock = ISR_LOCK_INITIALIZER( "thread zombies" ) |
---|
| 51 | }; |
---|
| 52 | |
---|
[300f6a48] | 53 | static void _Thread_Raise_real_priority( |
---|
[900d337f] | 54 | Thread_Control *the_thread, |
---|
[300f6a48] | 55 | Priority_Control priority |
---|
[900d337f] | 56 | ) |
---|
| 57 | { |
---|
[300f6a48] | 58 | Thread_queue_Context queue_context; |
---|
[900d337f] | 59 | |
---|
[5b6c290] | 60 | _Thread_queue_Context_initialize( &queue_context ); |
---|
[c09db57] | 61 | _Thread_queue_Context_clear_priority_updates( &queue_context ); |
---|
[5b6c290] | 62 | _Thread_Wait_acquire( the_thread, &queue_context ); |
---|
[900d337f] | 63 | |
---|
[300f6a48] | 64 | if ( priority < the_thread->Real_priority.priority ) { |
---|
| 65 | _Thread_Priority_change( |
---|
| 66 | the_thread, |
---|
| 67 | &the_thread->Real_priority, |
---|
| 68 | priority, |
---|
| 69 | false, |
---|
| 70 | &queue_context |
---|
| 71 | ); |
---|
| 72 | } |
---|
[900d337f] | 73 | |
---|
[300f6a48] | 74 | _Thread_Wait_release( the_thread, &queue_context ); |
---|
| 75 | _Thread_Priority_update( &queue_context ); |
---|
[7023d82c] | 76 | } |
---|
| 77 | |
---|
[232147dd] | 78 | typedef struct { |
---|
[631b3c8] | 79 | Thread_queue_Context Base; |
---|
| 80 | void *exit_value; |
---|
| 81 | } Thread_Join_context; |
---|
[232147dd] | 82 | |
---|
[54550e04] | 83 | static Thread_Control *_Thread_Join_flush_filter( |
---|
[631b3c8] | 84 | Thread_Control *the_thread, |
---|
| 85 | Thread_queue_Queue *queue, |
---|
| 86 | Thread_queue_Context *queue_context |
---|
[54550e04] | 87 | ) |
---|
| 88 | { |
---|
[631b3c8] | 89 | Thread_Join_context *join_context; |
---|
[54550e04] | 90 | |
---|
[631b3c8] | 91 | join_context = (Thread_Join_context *) queue_context; |
---|
[54550e04] | 92 | |
---|
[631b3c8] | 93 | the_thread->Wait.return_argument = join_context->exit_value; |
---|
[54550e04] | 94 | |
---|
| 95 | return the_thread; |
---|
| 96 | } |
---|
| 97 | |
---|
[232147dd] | 98 | static void _Thread_Wake_up_joining_threads( Thread_Control *the_thread ) |
---|
| 99 | { |
---|
[631b3c8] | 100 | Thread_Join_context join_context; |
---|
[232147dd] | 101 | |
---|
[631b3c8] | 102 | join_context.exit_value = the_thread->Life.exit_value; |
---|
[54550e04] | 103 | |
---|
[0e1d11f3] | 104 | _Thread_queue_Context_initialize( &join_context.Base ); |
---|
[114e408] | 105 | _Thread_queue_Acquire( &the_thread->Join_queue, &join_context.Base ); |
---|
[232147dd] | 106 | _Thread_queue_Flush_critical( |
---|
| 107 | &the_thread->Join_queue.Queue, |
---|
| 108 | THREAD_JOIN_TQ_OPERATIONS, |
---|
[54550e04] | 109 | _Thread_Join_flush_filter, |
---|
[631b3c8] | 110 | &join_context.Base |
---|
[232147dd] | 111 | ); |
---|
| 112 | } |
---|
| 113 | |
---|
[4b3251a] | 114 | static void _Thread_Add_to_zombie_chain( Thread_Control *the_thread ) |
---|
[1b1be254] | 115 | { |
---|
[232147dd] | 116 | ISR_lock_Context lock_context; |
---|
| 117 | Thread_Zombie_control *zombies; |
---|
[1b1be254] | 118 | |
---|
[4b3251a] | 119 | zombies = &_Thread_Zombies; |
---|
| 120 | _ISR_lock_ISR_disable_and_acquire( &zombies->Lock, &lock_context ); |
---|
| 121 | _Chain_Append_unprotected( &zombies->Chain, &the_thread->Object.Node ); |
---|
| 122 | _ISR_lock_Release_and_ISR_enable( &zombies->Lock, &lock_context ); |
---|
| 123 | } |
---|
| 124 | |
---|
| 125 | static void _Thread_Make_zombie( Thread_Control *the_thread ) |
---|
| 126 | { |
---|
[47d2464] | 127 | #if defined(RTEMS_SCORE_THREAD_ENABLE_RESOURCE_COUNT) |
---|
[6c7caa1a] | 128 | if ( _Thread_Owns_resources( the_thread ) ) { |
---|
[3a659b04] | 129 | _Internal_error( INTERNAL_ERROR_RESOURCE_IN_USE ); |
---|
[3f5f2ce] | 130 | } |
---|
[47d2464] | 131 | #endif |
---|
[3f5f2ce] | 132 | |
---|
[a92989a] | 133 | _Objects_Close( |
---|
| 134 | _Objects_Get_information_id( the_thread->Object.id ), |
---|
| 135 | &the_thread->Object |
---|
| 136 | ); |
---|
| 137 | |
---|
[1b1be254] | 138 | _Thread_Set_state( the_thread, STATES_ZOMBIE ); |
---|
| 139 | _Thread_queue_Extract_with_proxy( the_thread ); |
---|
[03b900d] | 140 | _Thread_Timer_remove( the_thread ); |
---|
[1b1be254] | 141 | |
---|
[4b3251a] | 142 | /* |
---|
| 143 | * Add the thread to the thread zombie chain before we wake up joining |
---|
| 144 | * threads, so that they are able to clean up the thread immediately. This |
---|
| 145 | * matters for SMP configurations. |
---|
| 146 | */ |
---|
| 147 | _Thread_Add_to_zombie_chain( the_thread ); |
---|
| 148 | |
---|
| 149 | _Thread_Wake_up_joining_threads( the_thread ); |
---|
[1b1be254] | 150 | } |
---|
| 151 | |
---|
| 152 | static void _Thread_Free( Thread_Control *the_thread ) |
---|
| 153 | { |
---|
[d7665823] | 154 | Thread_Information *information = (Thread_Information *) |
---|
| 155 | _Objects_Get_information_id( the_thread->Object.id ); |
---|
| 156 | |
---|
[1b1be254] | 157 | _User_extensions_Thread_delete( the_thread ); |
---|
[709f38a] | 158 | _User_extensions_Destroy_iterators( the_thread ); |
---|
[5eaf0e7] | 159 | _ISR_lock_Destroy( &the_thread->Keys.Lock ); |
---|
[df2177ab] | 160 | _Scheduler_Node_destroy( |
---|
[2dd098a] | 161 | _Thread_Scheduler_get_home( the_thread ), |
---|
[7f742432] | 162 | _Thread_Scheduler_get_home_node( the_thread ) |
---|
[df2177ab] | 163 | ); |
---|
[90de3001] | 164 | _ISR_lock_Destroy( &the_thread->Timer.Lock ); |
---|
[1b1be254] | 165 | |
---|
| 166 | /* |
---|
| 167 | * The thread might have been FP. So deal with that. |
---|
| 168 | */ |
---|
| 169 | #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) |
---|
| 170 | #if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE ) |
---|
| 171 | if ( _Thread_Is_allocated_fp( the_thread ) ) |
---|
| 172 | _Thread_Deallocate_fp(); |
---|
| 173 | #endif |
---|
| 174 | |
---|
| 175 | _Workspace_Free( the_thread->Start.fp_context ); |
---|
| 176 | #endif |
---|
| 177 | |
---|
[d7665823] | 178 | _Freechain_Put( |
---|
| 179 | &information->Free_thread_queue_heads, |
---|
| 180 | the_thread->Wait.spare_heads |
---|
| 181 | ); |
---|
| 182 | |
---|
[1b1be254] | 183 | /* |
---|
| 184 | * Free the rest of the memory associated with this task |
---|
| 185 | * and set the associated pointers to NULL for safety. |
---|
| 186 | */ |
---|
| 187 | _Thread_Stack_Free( the_thread ); |
---|
| 188 | |
---|
| 189 | _Workspace_Free( the_thread->Start.tls_area ); |
---|
| 190 | |
---|
[57947f1] | 191 | #if defined(RTEMS_SMP) |
---|
[07a32d19] | 192 | _ISR_lock_Destroy( &the_thread->Scheduler.Lock ); |
---|
[1fcac5ad] | 193 | _ISR_lock_Destroy( &the_thread->Wait.Lock.Default ); |
---|
[10e32a26] | 194 | _SMP_lock_Stats_destroy( &the_thread->Potpourri_stats ); |
---|
[57947f1] | 195 | #endif |
---|
| 196 | |
---|
[6e4f929] | 197 | _Thread_queue_Destroy( &the_thread->Join_queue ); |
---|
[b2e1bded] | 198 | _Context_Destroy( the_thread, &the_thread->Registers ); |
---|
[d7665823] | 199 | _Objects_Free( &information->Objects, &the_thread->Object ); |
---|
[1b1be254] | 200 | } |
---|
| 201 | |
---|
| 202 | static void _Thread_Wait_for_execution_stop( Thread_Control *the_thread ) |
---|
| 203 | { |
---|
| 204 | #if defined(RTEMS_SMP) |
---|
| 205 | /* |
---|
| 206 | * It is very unlikely that we see an executing thread here. It can happen |
---|
| 207 | * in case the thread termination sequence is interrupted by a slow interrupt |
---|
| 208 | * service on a remote processor. |
---|
| 209 | */ |
---|
[38b59a6] | 210 | while ( _Thread_Is_executing_on_a_processor( the_thread ) ) { |
---|
[1b1be254] | 211 | /* Wait */ |
---|
| 212 | } |
---|
| 213 | #else |
---|
| 214 | (void) the_thread; |
---|
| 215 | #endif |
---|
| 216 | } |
---|
| 217 | |
---|
| 218 | void _Thread_Kill_zombies( void ) |
---|
| 219 | { |
---|
| 220 | ISR_lock_Context lock_context; |
---|
| 221 | Thread_Zombie_control *zombies = &_Thread_Zombies; |
---|
| 222 | Thread_Control *the_thread; |
---|
| 223 | |
---|
| 224 | _ISR_lock_ISR_disable_and_acquire( &zombies->Lock, &lock_context ); |
---|
| 225 | |
---|
| 226 | the_thread = (Thread_Control *) _Chain_Get_unprotected( &zombies->Chain ); |
---|
| 227 | while ( the_thread != NULL ) { |
---|
| 228 | _ISR_lock_Release_and_ISR_enable( &zombies->Lock, &lock_context ); |
---|
| 229 | |
---|
| 230 | _Thread_Wait_for_execution_stop( the_thread ); |
---|
| 231 | _Thread_Free( the_thread ); |
---|
| 232 | |
---|
| 233 | _ISR_lock_ISR_disable_and_acquire( &zombies->Lock, &lock_context ); |
---|
| 234 | |
---|
| 235 | the_thread = (Thread_Control *) _Chain_Get_unprotected( &zombies->Chain ); |
---|
| 236 | } |
---|
| 237 | |
---|
| 238 | _ISR_lock_Release_and_ISR_enable( &zombies->Lock, &lock_context ); |
---|
| 239 | } |
---|
| 240 | |
---|
[9949d8a7] | 241 | static Thread_Life_state _Thread_Change_life_locked( |
---|
| 242 | Thread_Control *the_thread, |
---|
| 243 | Thread_Life_state clear, |
---|
| 244 | Thread_Life_state set, |
---|
| 245 | Thread_Life_state ignore |
---|
| 246 | ) |
---|
| 247 | { |
---|
| 248 | Thread_Life_state previous; |
---|
| 249 | Thread_Life_state state; |
---|
| 250 | |
---|
| 251 | previous = the_thread->Life.state; |
---|
| 252 | state = previous; |
---|
| 253 | state &= ~clear; |
---|
| 254 | state |= set; |
---|
| 255 | the_thread->Life.state = state; |
---|
| 256 | |
---|
| 257 | state &= ~ignore; |
---|
| 258 | |
---|
| 259 | if ( |
---|
| 260 | _Thread_Is_life_change_allowed( state ) |
---|
| 261 | && _Thread_Is_life_changing( state ) |
---|
| 262 | ) { |
---|
| 263 | the_thread->is_preemptible = the_thread->Start.is_preemptible; |
---|
| 264 | the_thread->budget_algorithm = the_thread->Start.budget_algorithm; |
---|
| 265 | the_thread->budget_callout = the_thread->Start.budget_callout; |
---|
| 266 | |
---|
| 267 | _Thread_Add_post_switch_action( |
---|
| 268 | the_thread, |
---|
| 269 | &the_thread->Life.Action, |
---|
| 270 | _Thread_Life_action_handler |
---|
| 271 | ); |
---|
| 272 | } |
---|
| 273 | |
---|
| 274 | return previous; |
---|
| 275 | } |
---|
| 276 | |
---|
[54550e04] | 277 | static Per_CPU_Control *_Thread_Wait_for_join( |
---|
| 278 | Thread_Control *executing, |
---|
| 279 | Per_CPU_Control *cpu_self |
---|
| 280 | ) |
---|
| 281 | { |
---|
| 282 | ISR_lock_Context lock_context; |
---|
| 283 | |
---|
| 284 | _Thread_State_acquire( executing, &lock_context ); |
---|
| 285 | |
---|
| 286 | if ( |
---|
| 287 | _Thread_Is_joinable( executing ) |
---|
| 288 | && _Thread_queue_Is_empty( &executing->Join_queue.Queue ) |
---|
| 289 | ) { |
---|
| 290 | _Thread_Set_state_locked( executing, STATES_WAITING_FOR_JOIN_AT_EXIT ); |
---|
| 291 | _Thread_State_release( executing, &lock_context ); |
---|
[ed24ed4e] | 292 | _Thread_Dispatch_direct( cpu_self ); |
---|
[54550e04] | 293 | |
---|
| 294 | /* Let other threads run */ |
---|
| 295 | |
---|
| 296 | cpu_self = _Thread_Dispatch_disable(); |
---|
| 297 | } else { |
---|
| 298 | _Thread_State_release( executing, &lock_context ); |
---|
| 299 | } |
---|
| 300 | |
---|
| 301 | return cpu_self; |
---|
| 302 | } |
---|
| 303 | |
---|
[5c731a83] | 304 | void _Thread_Life_action_handler( |
---|
[6e4f929] | 305 | Thread_Control *executing, |
---|
| 306 | Thread_Action *action, |
---|
| 307 | ISR_lock_Context *lock_context |
---|
[5c731a83] | 308 | ) |
---|
| 309 | { |
---|
[29e1ecab] | 310 | Thread_Life_state previous_life_state; |
---|
| 311 | Per_CPU_Control *cpu_self; |
---|
[1b1be254] | 312 | |
---|
[5c731a83] | 313 | (void) action; |
---|
[1b1be254] | 314 | |
---|
| 315 | previous_life_state = executing->Life.state; |
---|
[29e1ecab] | 316 | executing->Life.state = previous_life_state | THREAD_LIFE_PROTECTED; |
---|
[1b1be254] | 317 | |
---|
[6e4f929] | 318 | _Thread_State_release( executing, lock_context ); |
---|
[5c731a83] | 319 | |
---|
[1b1be254] | 320 | if ( _Thread_Is_life_terminating( previous_life_state ) ) { |
---|
| 321 | _User_extensions_Thread_terminate( executing ); |
---|
| 322 | } else { |
---|
| 323 | _Assert( _Thread_Is_life_restarting( previous_life_state ) ); |
---|
| 324 | |
---|
| 325 | _User_extensions_Thread_restart( executing ); |
---|
| 326 | } |
---|
[391ad3e] | 327 | |
---|
[29e1ecab] | 328 | cpu_self = _Thread_Dispatch_disable(); |
---|
[5c731a83] | 329 | |
---|
[1b1be254] | 330 | if ( _Thread_Is_life_terminating( previous_life_state ) ) { |
---|
[54550e04] | 331 | cpu_self = _Thread_Wait_for_join( executing, cpu_self ); |
---|
[1b1be254] | 332 | _Thread_Make_zombie( executing ); |
---|
[d78d529] | 333 | _Thread_Dispatch_direct( cpu_self ); |
---|
[e8d9b26] | 334 | RTEMS_UNREACHABLE(); |
---|
[29e1ecab] | 335 | } |
---|
[1b1be254] | 336 | |
---|
[29e1ecab] | 337 | _Assert( _Thread_Is_life_restarting( previous_life_state ) ); |
---|
[1b1be254] | 338 | |
---|
[29e1ecab] | 339 | _Thread_State_acquire( executing, lock_context ); |
---|
[1b1be254] | 340 | |
---|
[29e1ecab] | 341 | _Thread_Change_life_locked( |
---|
| 342 | executing, |
---|
| 343 | THREAD_LIFE_PROTECTED | THREAD_LIFE_RESTARTING, |
---|
| 344 | 0, |
---|
| 345 | 0 |
---|
| 346 | ); |
---|
[9388390] | 347 | |
---|
[29e1ecab] | 348 | _Thread_State_release( executing, lock_context ); |
---|
[9388390] | 349 | |
---|
[29e1ecab] | 350 | _Assert( |
---|
| 351 | _Watchdog_Get_state( &executing->Timer.Watchdog ) == WATCHDOG_INACTIVE |
---|
| 352 | ); |
---|
| 353 | _Assert( |
---|
| 354 | executing->current_state == STATES_READY |
---|
| 355 | || executing->current_state == STATES_SUSPENDED |
---|
| 356 | ); |
---|
[9388390] | 357 | |
---|
[29e1ecab] | 358 | _User_extensions_Destroy_iterators( executing ); |
---|
| 359 | _Thread_Load_environment( executing ); |
---|
[9388390] | 360 | |
---|
| 361 | #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) |
---|
[29e1ecab] | 362 | if ( executing->fp_context != NULL ) { |
---|
| 363 | _Context_Restore_fp( &executing->fp_context ); |
---|
| 364 | } |
---|
[9388390] | 365 | #endif |
---|
| 366 | |
---|
[29e1ecab] | 367 | _Context_Restart_self( &executing->Registers ); |
---|
| 368 | RTEMS_UNREACHABLE(); |
---|
[5c731a83] | 369 | } |
---|
| 370 | |
---|
[862a0ee] | 371 | static void _Thread_Add_life_change_request( Thread_Control *the_thread ) |
---|
| 372 | { |
---|
| 373 | uint32_t pending_requests; |
---|
| 374 | |
---|
| 375 | _Assert( _Thread_State_is_owner( the_thread ) ); |
---|
| 376 | |
---|
| 377 | pending_requests = the_thread->Life.pending_life_change_requests; |
---|
| 378 | the_thread->Life.pending_life_change_requests = pending_requests + 1; |
---|
| 379 | |
---|
| 380 | if ( pending_requests == 0 ) { |
---|
| 381 | _Thread_Set_state_locked( the_thread, STATES_LIFE_IS_CHANGING ); |
---|
| 382 | } |
---|
| 383 | } |
---|
| 384 | |
---|
| 385 | static void _Thread_Remove_life_change_request( Thread_Control *the_thread ) |
---|
| 386 | { |
---|
| 387 | ISR_lock_Context lock_context; |
---|
| 388 | uint32_t pending_requests; |
---|
| 389 | |
---|
| 390 | _Thread_State_acquire( the_thread, &lock_context ); |
---|
| 391 | |
---|
| 392 | pending_requests = the_thread->Life.pending_life_change_requests; |
---|
| 393 | the_thread->Life.pending_life_change_requests = pending_requests - 1; |
---|
| 394 | |
---|
| 395 | if ( pending_requests == 1 ) { |
---|
| 396 | /* |
---|
| 397 | * Do not remove states used for thread queues to avoid race conditions on |
---|
| 398 | * SMP configurations. We could interrupt an extract operation on another |
---|
| 399 | * processor disregarding the thread wait flags. Rely on |
---|
| 400 | * _Thread_queue_Extract_with_proxy() for removal of these states. |
---|
| 401 | */ |
---|
| 402 | _Thread_Clear_state_locked( |
---|
| 403 | the_thread, |
---|
| 404 | STATES_LIFE_IS_CHANGING | STATES_SUSPENDED |
---|
| 405 | | ( STATES_BLOCKED & ~STATES_LOCALLY_BLOCKED ) |
---|
| 406 | ); |
---|
| 407 | } |
---|
| 408 | |
---|
| 409 | _Thread_State_release( the_thread, &lock_context ); |
---|
| 410 | } |
---|
| 411 | |
---|
| 412 | static void _Thread_Finalize_life_change( |
---|
| 413 | Thread_Control *the_thread, |
---|
| 414 | Priority_Control priority |
---|
| 415 | ) |
---|
| 416 | { |
---|
| 417 | _Thread_queue_Extract_with_proxy( the_thread ); |
---|
| 418 | _Thread_Timer_remove( the_thread ); |
---|
[69dd99b] | 419 | _Thread_Raise_real_priority( the_thread, priority ); |
---|
[862a0ee] | 420 | _Thread_Remove_life_change_request( the_thread ); |
---|
| 421 | } |
---|
| 422 | |
---|
[232147dd] | 423 | void _Thread_Join( |
---|
[93306058] | 424 | Thread_Control *the_thread, |
---|
| 425 | States_Control waiting_for_join, |
---|
| 426 | Thread_Control *executing, |
---|
| 427 | Thread_queue_Context *queue_context |
---|
[232147dd] | 428 | ) |
---|
| 429 | { |
---|
| 430 | _Assert( the_thread != executing ); |
---|
| 431 | _Assert( _Thread_State_is_owner( the_thread ) ); |
---|
| 432 | |
---|
[54550e04] | 433 | executing->Wait.return_argument = NULL; |
---|
| 434 | |
---|
[620b23e] | 435 | _Thread_queue_Context_set_thread_state( queue_context, waiting_for_join ); |
---|
[a4217c6] | 436 | _Thread_queue_Enqueue( |
---|
[232147dd] | 437 | &the_thread->Join_queue.Queue, |
---|
| 438 | THREAD_JOIN_TQ_OPERATIONS, |
---|
| 439 | executing, |
---|
[93306058] | 440 | queue_context |
---|
[232147dd] | 441 | ); |
---|
| 442 | } |
---|
| 443 | |
---|
[54550e04] | 444 | static void _Thread_Set_exit_value( |
---|
| 445 | Thread_Control *the_thread, |
---|
| 446 | void *exit_value |
---|
| 447 | ) |
---|
| 448 | { |
---|
| 449 | the_thread->Life.exit_value = exit_value; |
---|
| 450 | } |
---|
| 451 | |
---|
| 452 | void _Thread_Cancel( |
---|
| 453 | Thread_Control *the_thread, |
---|
| 454 | Thread_Control *executing, |
---|
| 455 | void *exit_value |
---|
| 456 | ) |
---|
[1b1be254] | 457 | { |
---|
[ef09017] | 458 | ISR_lock_Context lock_context; |
---|
| 459 | Thread_Life_state previous; |
---|
| 460 | Per_CPU_Control *cpu_self; |
---|
| 461 | Priority_Control priority; |
---|
| 462 | |
---|
[b7f5e391] | 463 | _Assert( the_thread != executing ); |
---|
[1b1be254] | 464 | |
---|
[ef09017] | 465 | _Thread_State_acquire( the_thread, &lock_context ); |
---|
| 466 | |
---|
[54550e04] | 467 | _Thread_Set_exit_value( the_thread, exit_value ); |
---|
[ef09017] | 468 | previous = _Thread_Change_life_locked( |
---|
| 469 | the_thread, |
---|
| 470 | 0, |
---|
| 471 | THREAD_LIFE_TERMINATING, |
---|
| 472 | 0 |
---|
| 473 | ); |
---|
| 474 | |
---|
| 475 | cpu_self = _Thread_Dispatch_disable_critical( &lock_context ); |
---|
[b20b736] | 476 | priority = _Thread_Get_priority( executing ); |
---|
[ef09017] | 477 | |
---|
[1b1be254] | 478 | if ( _States_Is_dormant( the_thread->current_state ) ) { |
---|
[ef09017] | 479 | _Thread_State_release( the_thread, &lock_context ); |
---|
[1b1be254] | 480 | _Thread_Make_zombie( the_thread ); |
---|
[ef09017] | 481 | } else if ( _Thread_Is_life_change_allowed( previous ) ) { |
---|
| 482 | _Thread_Add_life_change_request( the_thread ); |
---|
| 483 | _Thread_State_release( the_thread, &lock_context ); |
---|
| 484 | |
---|
| 485 | _Thread_Finalize_life_change( the_thread, priority ); |
---|
[1b1be254] | 486 | } else { |
---|
[ef09017] | 487 | _Thread_Add_life_change_request( the_thread ); |
---|
| 488 | _Thread_Clear_state_locked( the_thread, STATES_SUSPENDED ); |
---|
| 489 | _Thread_State_release( the_thread, &lock_context ); |
---|
| 490 | |
---|
| 491 | _Thread_Raise_real_priority( the_thread, priority ); |
---|
| 492 | _Thread_Remove_life_change_request( the_thread ); |
---|
[1b1be254] | 493 | } |
---|
[ef09017] | 494 | |
---|
| 495 | _Thread_Dispatch_enable( cpu_self ); |
---|
[5c731a83] | 496 | } |
---|
[05279b84] | 497 | |
---|
[125f248] | 498 | static void _Thread_Close_enqueue_callout( |
---|
| 499 | Thread_queue_Queue *queue, |
---|
| 500 | Thread_Control *the_thread, |
---|
[c3105894] | 501 | Per_CPU_Control *cpu_self, |
---|
[125f248] | 502 | Thread_queue_Context *queue_context |
---|
| 503 | ) |
---|
[232147dd] | 504 | { |
---|
[125f248] | 505 | Thread_Close_context *context; |
---|
| 506 | |
---|
| 507 | context = (Thread_Close_context *) queue_context; |
---|
| 508 | _Thread_Cancel( context->cancel, the_thread, NULL ); |
---|
| 509 | } |
---|
[232147dd] | 510 | |
---|
[125f248] | 511 | void _Thread_Close( |
---|
| 512 | Thread_Control *the_thread, |
---|
| 513 | Thread_Control *executing, |
---|
| 514 | Thread_Close_context *context |
---|
| 515 | ) |
---|
| 516 | { |
---|
| 517 | context->cancel = the_thread; |
---|
| 518 | _Thread_queue_Context_set_enqueue_callout( |
---|
| 519 | &context->Base, |
---|
| 520 | _Thread_Close_enqueue_callout |
---|
| 521 | ); |
---|
| 522 | _Thread_State_acquire_critical( |
---|
| 523 | the_thread, |
---|
| 524 | &context->Base.Lock_context.Lock_context |
---|
| 525 | ); |
---|
[232147dd] | 526 | _Thread_Join( |
---|
| 527 | the_thread, |
---|
| 528 | STATES_WAITING_FOR_JOIN, |
---|
| 529 | executing, |
---|
[125f248] | 530 | &context->Base |
---|
[232147dd] | 531 | ); |
---|
| 532 | } |
---|
| 533 | |
---|
[54550e04] | 534 | void _Thread_Exit( |
---|
| 535 | Thread_Control *executing, |
---|
| 536 | Thread_Life_state set, |
---|
| 537 | void *exit_value |
---|
| 538 | ) |
---|
[b7f5e391] | 539 | { |
---|
[c99eb50b] | 540 | ISR_lock_Context lock_context; |
---|
| 541 | |
---|
| 542 | _Assert( |
---|
| 543 | _Watchdog_Get_state( &executing->Timer.Watchdog ) == WATCHDOG_INACTIVE |
---|
| 544 | ); |
---|
| 545 | _Assert( |
---|
| 546 | executing->current_state == STATES_READY |
---|
| 547 | || executing->current_state == STATES_SUSPENDED |
---|
| 548 | ); |
---|
| 549 | |
---|
| 550 | _Thread_State_acquire( executing, &lock_context ); |
---|
[54550e04] | 551 | _Thread_Set_exit_value( executing, exit_value ); |
---|
[c99eb50b] | 552 | _Thread_Change_life_locked( |
---|
[b7f5e391] | 553 | executing, |
---|
[c99eb50b] | 554 | 0, |
---|
[54550e04] | 555 | set, |
---|
[da826560] | 556 | THREAD_LIFE_PROTECTED | THREAD_LIFE_CHANGE_DEFERRED |
---|
[b7f5e391] | 557 | ); |
---|
[c99eb50b] | 558 | _Thread_State_release( executing, &lock_context ); |
---|
[b7f5e391] | 559 | } |
---|
| 560 | |
---|
[9388390] | 561 | bool _Thread_Restart_other( |
---|
[ccd5434] | 562 | Thread_Control *the_thread, |
---|
[9388390] | 563 | const Thread_Entry_information *entry, |
---|
| 564 | ISR_lock_Context *lock_context |
---|
[5c731a83] | 565 | ) |
---|
| 566 | { |
---|
[862a0ee] | 567 | Thread_Life_state previous; |
---|
| 568 | Per_CPU_Control *cpu_self; |
---|
[084c5cc] | 569 | |
---|
[9388390] | 570 | _Thread_State_acquire_critical( the_thread, lock_context ); |
---|
[05279b84] | 571 | |
---|
[9388390] | 572 | if ( _States_Is_dormant( the_thread->current_state ) ) { |
---|
| 573 | _Thread_State_release( the_thread, lock_context ); |
---|
| 574 | return false; |
---|
[05df0a8] | 575 | } |
---|
[05279b84] | 576 | |
---|
[9388390] | 577 | the_thread->Start.Entry = *entry; |
---|
[862a0ee] | 578 | previous = _Thread_Change_life_locked( |
---|
| 579 | the_thread, |
---|
| 580 | 0, |
---|
| 581 | THREAD_LIFE_RESTARTING, |
---|
| 582 | 0 |
---|
| 583 | ); |
---|
[9388390] | 584 | |
---|
| 585 | cpu_self = _Thread_Dispatch_disable_critical( lock_context ); |
---|
| 586 | |
---|
[862a0ee] | 587 | if ( _Thread_Is_life_change_allowed( previous ) ) { |
---|
| 588 | _Thread_Add_life_change_request( the_thread ); |
---|
| 589 | _Thread_State_release( the_thread, lock_context ); |
---|
| 590 | |
---|
| 591 | _Thread_Finalize_life_change( |
---|
| 592 | the_thread, |
---|
| 593 | the_thread->Start.initial_priority |
---|
| 594 | ); |
---|
| 595 | } else { |
---|
| 596 | _Thread_Clear_state_locked( the_thread, STATES_SUSPENDED ); |
---|
| 597 | _Thread_State_release( the_thread, lock_context ); |
---|
| 598 | } |
---|
[9388390] | 599 | |
---|
| 600 | _Thread_Dispatch_enable( cpu_self ); |
---|
| 601 | return true; |
---|
| 602 | } |
---|
| 603 | |
---|
| 604 | void _Thread_Restart_self( |
---|
| 605 | Thread_Control *executing, |
---|
| 606 | const Thread_Entry_information *entry, |
---|
| 607 | ISR_lock_Context *lock_context |
---|
| 608 | ) |
---|
| 609 | { |
---|
[300f6a48] | 610 | Per_CPU_Control *cpu_self; |
---|
| 611 | Thread_queue_Context queue_context; |
---|
[9388390] | 612 | |
---|
| 613 | _Assert( |
---|
| 614 | _Watchdog_Get_state( &executing->Timer.Watchdog ) == WATCHDOG_INACTIVE |
---|
| 615 | ); |
---|
| 616 | _Assert( |
---|
| 617 | executing->current_state == STATES_READY |
---|
| 618 | || executing->current_state == STATES_SUSPENDED |
---|
| 619 | ); |
---|
| 620 | |
---|
[5b6c290] | 621 | _Thread_queue_Context_initialize( &queue_context ); |
---|
| 622 | _Thread_queue_Context_clear_priority_updates( &queue_context ); |
---|
[9388390] | 623 | _Thread_State_acquire_critical( executing, lock_context ); |
---|
| 624 | |
---|
| 625 | executing->Start.Entry = *entry; |
---|
| 626 | _Thread_Change_life_locked( |
---|
| 627 | executing, |
---|
| 628 | 0, |
---|
| 629 | THREAD_LIFE_RESTARTING, |
---|
[da826560] | 630 | THREAD_LIFE_PROTECTED | THREAD_LIFE_CHANGE_DEFERRED |
---|
[9388390] | 631 | ); |
---|
| 632 | |
---|
| 633 | cpu_self = _Thread_Dispatch_disable_critical( lock_context ); |
---|
| 634 | _Thread_State_release( executing, lock_context ); |
---|
| 635 | |
---|
[300f6a48] | 636 | _Thread_Wait_acquire_default( executing, lock_context ); |
---|
| 637 | _Thread_Priority_change( |
---|
[9388390] | 638 | executing, |
---|
[300f6a48] | 639 | &executing->Real_priority, |
---|
[9388390] | 640 | executing->Start.initial_priority, |
---|
[300f6a48] | 641 | false, |
---|
| 642 | &queue_context |
---|
[9388390] | 643 | ); |
---|
[300f6a48] | 644 | _Thread_Wait_release_default( executing, lock_context ); |
---|
[9388390] | 645 | |
---|
[300f6a48] | 646 | _Thread_Priority_update( &queue_context ); |
---|
[ed24ed4e] | 647 | _Thread_Dispatch_direct( cpu_self ); |
---|
[9388390] | 648 | RTEMS_UNREACHABLE(); |
---|
[05df0a8] | 649 | } |
---|
[1b1be254] | 650 | |
---|
[da826560] | 651 | Thread_Life_state _Thread_Change_life( |
---|
[9949d8a7] | 652 | Thread_Life_state clear, |
---|
| 653 | Thread_Life_state set, |
---|
| 654 | Thread_Life_state ignore |
---|
| 655 | ) |
---|
[1b1be254] | 656 | { |
---|
[6e4f929] | 657 | ISR_lock_Context lock_context; |
---|
| 658 | Thread_Control *executing; |
---|
[9949d8a7] | 659 | Per_CPU_Control *cpu_self; |
---|
| 660 | Thread_Life_state previous; |
---|
[1b1be254] | 661 | |
---|
[6e4f929] | 662 | executing = _Thread_State_acquire_for_executing( &lock_context ); |
---|
[1b1be254] | 663 | |
---|
[9949d8a7] | 664 | previous = _Thread_Change_life_locked( executing, clear, set, ignore ); |
---|
[1b1be254] | 665 | |
---|
[9949d8a7] | 666 | cpu_self = _Thread_Dispatch_disable_critical( &lock_context ); |
---|
[6e4f929] | 667 | _Thread_State_release( executing, &lock_context ); |
---|
[9949d8a7] | 668 | _Thread_Dispatch_enable( cpu_self ); |
---|
[1b1be254] | 669 | |
---|
[9949d8a7] | 670 | return previous; |
---|
| 671 | } |
---|
[1b1be254] | 672 | |
---|
[9949d8a7] | 673 | Thread_Life_state _Thread_Set_life_protection( Thread_Life_state state ) |
---|
| 674 | { |
---|
| 675 | return _Thread_Change_life( |
---|
| 676 | THREAD_LIFE_PROTECTED, |
---|
| 677 | state & THREAD_LIFE_PROTECTED, |
---|
| 678 | 0 |
---|
| 679 | ); |
---|
[1b1be254] | 680 | } |
---|