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