File indexing completed on 2025-05-11 08:24:27
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041 #ifdef HAVE_CONFIG_H
0042 #include "config.h"
0043 #endif
0044
0045 #include <rtems/score/threadimpl.h>
0046 #include <rtems/score/apimutex.h>
0047 #include <rtems/score/assert.h>
0048 #include <rtems/score/chainimpl.h>
0049 #include <rtems/score/isrlock.h>
0050 #include <rtems/score/schedulerimpl.h>
0051 #include <rtems/score/sysstate.h>
0052 #include <rtems/score/threadqimpl.h>
0053 #include <rtems/score/userextimpl.h>
0054 #include <rtems/score/watchdogimpl.h>
0055
0056 #include <pthread.h>
0057
0058 #define THREAD_JOIN_TQ_OPERATIONS &_Thread_queue_Operations_priority_inherit
0059
0060 static void _Thread_Life_action_handler(
0061 Thread_Control *executing,
0062 Thread_Action *action,
0063 ISR_lock_Context *lock_context
0064 );
0065
0066 Thread_Zombie_registry _Thread_Zombies = {
0067 #if defined(RTEMS_SMP)
0068 .Lock = ISR_LOCK_INITIALIZER( "Thread Zombies" ),
0069 #endif
0070 .Chain = CHAIN_INITIALIZER_EMPTY( _Thread_Zombies.Chain )
0071 };
0072
0073 typedef struct {
0074 Thread_queue_Context Base;
0075 void *exit_value;
0076 } Thread_Join_context;
0077
0078 static Thread_Control *_Thread_Join_flush_filter(
0079 Thread_Control *the_thread,
0080 Thread_queue_Queue *queue,
0081 Thread_queue_Context *queue_context
0082 )
0083 {
0084 Thread_Join_context *join_context;
0085
0086 (void) queue;
0087 join_context = (Thread_Join_context *) queue_context;
0088
0089 the_thread->Wait.return_argument = join_context->exit_value;
0090
0091 return the_thread;
0092 }
0093
0094 static void _Thread_Wake_up_joining_threads( Thread_Control *the_thread )
0095 {
0096 Thread_Join_context join_context;
0097
0098 join_context.exit_value = the_thread->Life.exit_value;
0099
0100 _Thread_queue_Context_initialize( &join_context.Base );
0101 _Thread_queue_Acquire( &the_thread->Join_queue, &join_context.Base );
0102 _Thread_queue_Flush_critical(
0103 &the_thread->Join_queue.Queue,
0104 THREAD_JOIN_TQ_OPERATIONS,
0105 _Thread_Join_flush_filter,
0106 &join_context.Base
0107 );
0108 }
0109
0110 static void _Thread_Add_to_zombie_registry( Thread_Control *the_thread )
0111 {
0112 ISR_lock_Context lock_context;
0113 Thread_Zombie_registry *zombies;
0114
0115 zombies = &_Thread_Zombies;
0116 _ISR_lock_ISR_disable_and_acquire( &zombies->Lock, &lock_context );
0117 _Chain_Append_unprotected( &zombies->Chain, &the_thread->Object.Node );
0118 _ISR_lock_Release_and_ISR_enable( &zombies->Lock, &lock_context );
0119 }
0120
0121 static void _Thread_Make_zombie( Thread_Control *the_thread )
0122 {
0123 Thread_Information *information;
0124
0125 #if defined(RTEMS_SCORE_THREAD_ENABLE_RESOURCE_COUNT)
0126 if ( _Thread_Owns_resources( the_thread ) ) {
0127 _Internal_error( INTERNAL_ERROR_RESOURCE_IN_USE );
0128 }
0129 #endif
0130
0131 information = _Thread_Get_objects_information( the_thread );
0132 _Objects_Close( &information->Objects, &the_thread->Object );
0133
0134 _Thread_Set_state( the_thread, STATES_ZOMBIE );
0135 _Thread_Timer_remove_and_continue( the_thread, STATUS_INTERNAL_ERROR );
0136
0137
0138
0139
0140
0141
0142 _Thread_Add_to_zombie_registry( the_thread );
0143
0144 _Thread_Wake_up_joining_threads( the_thread );
0145 }
0146
0147 static void _Thread_Wait_for_execution_stop( const Thread_Control *the_thread )
0148 {
0149 #if defined(RTEMS_SMP)
0150
0151
0152
0153
0154
0155 while ( _Thread_Is_executing_on_a_processor( the_thread ) ) {
0156
0157 }
0158 #else
0159 (void) the_thread;
0160 #endif
0161 }
0162
0163 static Thread_Control *_Thread_Get_zombie( Thread_Zombie_registry *zombies )
0164 {
0165 return (Thread_Control *) _Chain_Get_unprotected( &zombies->Chain );
0166 }
0167
0168 void _Thread_Kill_zombies( void )
0169 {
0170 ISR_lock_Context lock_context;
0171 Thread_Zombie_registry *zombies;
0172 Thread_Control *the_thread;
0173
0174 zombies = &_Thread_Zombies;
0175 _ISR_lock_ISR_disable_and_acquire( &zombies->Lock, &lock_context );
0176
0177 while ( ( the_thread = _Thread_Get_zombie( zombies ) ) != NULL ) {
0178 Thread_Information *information;
0179
0180 _ISR_lock_Release_and_ISR_enable( &zombies->Lock, &lock_context );
0181
0182 _Thread_Wait_for_execution_stop( the_thread );
0183 information = _Thread_Get_objects_information( the_thread );
0184 _Thread_Free( information, the_thread );
0185
0186 _ISR_lock_ISR_disable_and_acquire( &zombies->Lock, &lock_context );
0187 }
0188
0189 _ISR_lock_Release_and_ISR_enable( &zombies->Lock, &lock_context );
0190 }
0191
0192 static Thread_Life_state _Thread_Change_life_locked(
0193 Thread_Control *the_thread,
0194 Thread_Life_state life_states_to_clear,
0195 Thread_Life_state life_states_to_set,
0196 Thread_Life_state ignored_life_states
0197 )
0198 {
0199 Thread_Life_state previous;
0200 Thread_Life_state state;
0201
0202 previous = the_thread->Life.state;
0203 state = previous;
0204 state &= ~life_states_to_clear;
0205 state |= life_states_to_set;
0206 the_thread->Life.state = state;
0207
0208 state &= ~ignored_life_states;
0209
0210 if (
0211 _Thread_Is_life_change_allowed( state )
0212 && _Thread_Is_life_changing( state )
0213 ) {
0214 _Thread_Add_post_switch_action(
0215 the_thread,
0216 &the_thread->Life.Action,
0217 _Thread_Life_action_handler
0218 );
0219 }
0220
0221 return previous;
0222 }
0223
0224 static Per_CPU_Control *_Thread_Wait_for_join(
0225 Thread_Control *executing,
0226 Per_CPU_Control *cpu_self
0227 )
0228 {
0229 ISR_lock_Context lock_context;
0230
0231 _Thread_State_acquire( executing, &lock_context );
0232
0233 if (
0234 _Thread_Is_joinable( executing )
0235 && _Thread_queue_Is_empty( &executing->Join_queue.Queue )
0236 ) {
0237 _Thread_Set_state_locked( executing, STATES_WAITING_FOR_JOIN_AT_EXIT );
0238 _Thread_State_release( executing, &lock_context );
0239 _Thread_Dispatch_direct( cpu_self );
0240
0241
0242
0243 cpu_self = _Thread_Dispatch_disable();
0244 } else {
0245 _Thread_State_release( executing, &lock_context );
0246 }
0247
0248 return cpu_self;
0249 }
0250
0251 void _Thread_Life_action_handler(
0252 Thread_Control *executing,
0253 Thread_Action *action,
0254 ISR_lock_Context *lock_context
0255 )
0256 {
0257 Thread_Life_state previous_life_state;
0258 Per_CPU_Control *cpu_self;
0259
0260 (void) action;
0261
0262 previous_life_state = executing->Life.state;
0263 executing->Life.state = previous_life_state | THREAD_LIFE_PROTECTED;
0264
0265 _Thread_State_release( executing, lock_context );
0266
0267 if ( _Thread_Is_life_terminating( previous_life_state ) ) {
0268 _User_extensions_Thread_terminate( executing );
0269 } else {
0270 _Assert( _Thread_Is_life_restarting( previous_life_state ) );
0271
0272 _User_extensions_Thread_restart( executing );
0273 }
0274
0275 cpu_self = _Thread_Dispatch_disable();
0276
0277 if ( _Thread_Is_life_terminating( previous_life_state ) ) {
0278 cpu_self = _Thread_Wait_for_join( executing, cpu_self );
0279 _Thread_Make_zombie( executing );
0280 _Thread_Dispatch_direct_no_return( cpu_self );
0281 RTEMS_UNREACHABLE();
0282 }
0283
0284 _Assert( _Thread_Is_life_restarting( previous_life_state ) );
0285
0286 _Thread_State_acquire( executing, lock_context );
0287
0288
0289
0290
0291
0292
0293
0294 _Assert(
0295 executing->current_state == STATES_READY
0296 || executing->current_state == STATES_SUSPENDED
0297 || executing->current_state == STATES_LIFE_IS_CHANGING
0298 );
0299
0300 _Thread_Change_life_locked(
0301 executing,
0302 THREAD_LIFE_PROTECTED | THREAD_LIFE_RESTARTING,
0303 0,
0304 0
0305 );
0306
0307 _Thread_State_release( executing, lock_context );
0308
0309 _Assert(
0310 _Watchdog_Get_state( &executing->Timer.Watchdog ) == WATCHDOG_INACTIVE
0311 );
0312
0313 _User_extensions_Destroy_iterators( executing );
0314 _Thread_Load_environment( executing );
0315
0316 #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
0317 if ( executing->fp_context != NULL ) {
0318 _Context_Restore_fp( &executing->fp_context );
0319 }
0320 #endif
0321
0322 _Context_Restart_self( &executing->Registers );
0323 RTEMS_UNREACHABLE();
0324 }
0325
0326 static void _Thread_Add_life_change_request( Thread_Control *the_thread )
0327 {
0328 uint32_t pending_requests;
0329
0330 _Assert( _Thread_State_is_owner( the_thread ) );
0331
0332 pending_requests = the_thread->Life.pending_life_change_requests;
0333 the_thread->Life.pending_life_change_requests = pending_requests + 1;
0334
0335 if ( pending_requests == 0 ) {
0336 _Thread_Set_state_locked( the_thread, STATES_LIFE_IS_CHANGING );
0337 }
0338 }
0339
0340 static void _Thread_Remove_life_change_request( Thread_Control *the_thread )
0341 {
0342 ISR_lock_Context lock_context;
0343 uint32_t pending_requests;
0344
0345 _Thread_State_acquire( the_thread, &lock_context );
0346
0347 pending_requests = the_thread->Life.pending_life_change_requests;
0348 the_thread->Life.pending_life_change_requests = pending_requests - 1;
0349
0350 if ( pending_requests == 1 ) {
0351
0352
0353
0354
0355
0356
0357 _Thread_Clear_state_locked(
0358 the_thread,
0359 STATES_LIFE_IS_CHANGING | STATES_SUSPENDED
0360 | ( STATES_BLOCKED & ~STATES_LOCALLY_BLOCKED )
0361 );
0362 }
0363
0364 _Thread_State_release( the_thread, &lock_context );
0365 }
0366
0367 static void _Thread_Clear_waiting_for_join_at_exit(
0368 Thread_queue_Queue *queue,
0369 Thread_Control *the_thread,
0370 Per_CPU_Control *cpu_self,
0371 Thread_queue_Context *queue_context
0372 )
0373 {
0374 (void) the_thread;
0375 (void) cpu_self;
0376 (void) queue_context;
0377 _Thread_Clear_state( queue->owner, STATES_WAITING_FOR_JOIN_AT_EXIT );
0378 }
0379
0380 Status_Control _Thread_Join(
0381 Thread_Control *the_thread,
0382 States_Control waiting_for_join,
0383 Thread_Control *executing,
0384 Thread_queue_Context *queue_context
0385 )
0386 {
0387 _Assert( _Thread_State_is_owner( the_thread ) );
0388
0389 executing->Wait.return_argument = NULL;
0390 _Thread_queue_Context_set_enqueue_callout(
0391 queue_context,
0392 _Thread_Clear_waiting_for_join_at_exit
0393 );
0394 _Thread_queue_Context_set_deadlock_callout(
0395 queue_context,
0396 _Thread_queue_Deadlock_status
0397 );
0398 _Thread_queue_Context_set_thread_state( queue_context, waiting_for_join );
0399 _Thread_queue_Enqueue(
0400 &the_thread->Join_queue.Queue,
0401 THREAD_JOIN_TQ_OPERATIONS,
0402 executing,
0403 queue_context
0404 );
0405 return _Thread_Wait_get_status( executing );
0406 }
0407
0408 static void _Thread_Set_exit_value(
0409 Thread_Control *the_thread,
0410 void *exit_value
0411 )
0412 {
0413 the_thread->Life.exit_value = exit_value;
0414 }
0415
0416 static void _Thread_Try_life_change_request(
0417 Thread_Control *the_thread,
0418 Thread_Life_state previous,
0419 ISR_lock_Context *lock_context
0420 )
0421 {
0422 if ( _Thread_Is_life_change_allowed( previous ) ) {
0423 _Thread_Add_life_change_request( the_thread );
0424 _Thread_State_release( the_thread, lock_context );
0425
0426 _Thread_Timer_remove_and_continue( the_thread, STATUS_INTERNAL_ERROR );
0427 _Thread_Remove_life_change_request( the_thread );
0428 } else {
0429 _Thread_Clear_state_locked( the_thread, STATES_SUSPENDED );
0430 _Thread_State_release( the_thread, lock_context );
0431 }
0432 }
0433
0434 Thread_Cancel_state _Thread_Cancel(
0435 Thread_Control *the_thread,
0436 Thread_Control *executing,
0437 Thread_Life_state life_states_to_clear
0438 )
0439 {
0440 ISR_lock_Context lock_context;
0441 Thread_Life_state previous;
0442
0443 _Assert( the_thread != executing );
0444
0445 _Thread_State_acquire( the_thread, &lock_context );
0446
0447 _Thread_Set_exit_value( the_thread, PTHREAD_CANCELED );
0448 previous = _Thread_Change_life_locked(
0449 the_thread,
0450 life_states_to_clear,
0451 THREAD_LIFE_TERMINATING,
0452 0
0453 );
0454
0455 if ( _States_Is_dormant( the_thread->current_state ) ) {
0456 _Thread_State_release( the_thread, &lock_context );
0457 _Thread_Make_zombie( the_thread );
0458 return THREAD_CANCEL_DONE;
0459 }
0460
0461 _Thread_Try_life_change_request( the_thread, previous, &lock_context );
0462 return THREAD_CANCEL_IN_PROGRESS;
0463 }
0464
0465 Status_Control _Thread_Close(
0466 Thread_Control *the_thread,
0467 Thread_Control *executing,
0468 Thread_queue_Context *queue_context
0469 )
0470 {
0471 Per_CPU_Control *cpu_self;
0472 Thread_Cancel_state cancel_state;
0473
0474 cpu_self = _Thread_Dispatch_disable_critical(
0475 &queue_context->Lock_context.Lock_context
0476 );
0477 _ISR_lock_ISR_enable( &queue_context->Lock_context.Lock_context );
0478
0479 cancel_state = _Thread_Cancel( the_thread, executing, THREAD_LIFE_DETACHED );
0480
0481 if ( cancel_state == THREAD_CANCEL_DONE ) {
0482 _Thread_Dispatch_enable( cpu_self );
0483 return STATUS_SUCCESSFUL;
0484 }
0485
0486 _ISR_lock_ISR_disable( &queue_context->Lock_context.Lock_context );
0487 _Thread_Dispatch_unnest( cpu_self );
0488 _Thread_State_acquire_critical(
0489 the_thread,
0490 &queue_context->Lock_context.Lock_context
0491 );
0492
0493 return _Thread_Join(
0494 the_thread,
0495 STATES_WAITING_FOR_JOIN,
0496 executing,
0497 queue_context
0498 );
0499 }
0500
0501 RTEMS_NO_RETURN void _Thread_Exit(
0502 void *exit_value,
0503 Thread_Life_state life_states_to_set
0504 )
0505 {
0506 Per_CPU_Control *cpu_self;
0507 Thread_Control *executing;
0508 ISR_lock_Context lock_context;
0509
0510 _ISR_lock_ISR_disable( &lock_context );
0511 cpu_self = _Thread_Dispatch_disable_critical( &lock_context );
0512 executing = _Per_CPU_Get_executing( cpu_self );
0513
0514 _Assert(
0515 _Watchdog_Get_state( &executing->Timer.Watchdog ) == WATCHDOG_INACTIVE
0516 );
0517 _Assert(
0518 executing->current_state == STATES_READY
0519 || executing->current_state == STATES_SUSPENDED
0520 );
0521
0522 _Thread_State_acquire_critical( executing, &lock_context );
0523 _Thread_Set_exit_value( executing, exit_value );
0524 _Thread_Change_life_locked(
0525 executing,
0526 0,
0527 life_states_to_set,
0528 THREAD_LIFE_PROTECTED | THREAD_LIFE_CHANGE_DEFERRED
0529 );
0530 _Thread_State_release( executing, &lock_context );
0531
0532 _Thread_Dispatch_direct_no_return( cpu_self );
0533 RTEMS_UNREACHABLE();
0534 }
0535
0536 Status_Control _Thread_Restart(
0537 Thread_Control *the_thread,
0538 const Thread_Entry_information *entry,
0539 ISR_lock_Context *lock_context
0540 )
0541 {
0542 Thread_Life_state previous;
0543 Per_CPU_Control *cpu_self;
0544 bool is_self_restart;
0545 Thread_Life_state ignored_life_states;
0546 Thread_queue_Context queue_context;
0547
0548 _Thread_State_acquire_critical( the_thread, lock_context );
0549
0550 if ( _States_Is_dormant( the_thread->current_state ) ) {
0551 _Thread_State_release( the_thread, lock_context );
0552 return STATUS_INCORRECT_STATE;
0553 }
0554
0555 cpu_self = _Thread_Dispatch_disable_critical( lock_context );
0556 is_self_restart = ( the_thread == _Per_CPU_Get_executing( cpu_self ) &&
0557 !_Per_CPU_Is_ISR_in_progress( cpu_self ) );
0558
0559 if ( is_self_restart ) {
0560 ignored_life_states = THREAD_LIFE_PROTECTED | THREAD_LIFE_CHANGE_DEFERRED;
0561 } else {
0562 ignored_life_states = 0;
0563 }
0564
0565 the_thread->Start.Entry = *entry;
0566 previous = _Thread_Change_life_locked(
0567 the_thread,
0568 0,
0569 THREAD_LIFE_RESTARTING,
0570 ignored_life_states
0571 );
0572 _Thread_Try_life_change_request( the_thread, previous, lock_context );
0573
0574 _Thread_queue_Context_initialize( &queue_context );
0575 _Thread_queue_Context_clear_priority_updates( &queue_context );
0576 _Thread_Wait_acquire( the_thread, &queue_context );
0577 _Thread_Priority_change(
0578 the_thread,
0579 &the_thread->Real_priority,
0580 the_thread->Start.initial_priority,
0581 PRIORITY_GROUP_LAST,
0582 &queue_context
0583 );
0584 _Thread_Wait_release( the_thread, &queue_context );
0585
0586 _Thread_Priority_update( &queue_context );
0587
0588 if ( is_self_restart ) {
0589 _Thread_Dispatch_direct_no_return( cpu_self );
0590 } else {
0591 _Thread_Dispatch_enable( cpu_self );
0592 }
0593
0594 return STATUS_SUCCESSFUL;
0595 }
0596
0597 Thread_Life_state _Thread_Change_life(
0598 Thread_Life_state life_states_to_clear,
0599 Thread_Life_state life_states_to_set,
0600 Thread_Life_state ignored_life_states
0601 )
0602 {
0603 ISR_lock_Context lock_context;
0604 Thread_Control *executing;
0605 Per_CPU_Control *cpu_self;
0606 Thread_Life_state previous;
0607
0608 executing = _Thread_State_acquire_for_executing( &lock_context );
0609
0610 previous = _Thread_Change_life_locked(
0611 executing,
0612 life_states_to_clear,
0613 life_states_to_set,
0614 ignored_life_states
0615 );
0616
0617 cpu_self = _Thread_Dispatch_disable_critical( &lock_context );
0618 _Thread_State_release( executing, &lock_context );
0619 _Thread_Dispatch_enable( cpu_self );
0620
0621 return previous;
0622 }
0623
0624 Thread_Life_state _Thread_Set_life_protection( Thread_Life_state state )
0625 {
0626 return _Thread_Change_life(
0627 THREAD_LIFE_PROTECTED,
0628 state & THREAD_LIFE_PROTECTED,
0629 0
0630 );
0631 }