Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:27

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSScoreThread
0007  *
0008  * @brief This source file contains the implementation of _Thread_Cancel(),
0009  *   _Thread_Change_life(), _Thread_Close(), _Thread_Exit(), _Thread_Join(),
0010  *   _Thread_Kill_zombies(), _Thread_Restart(), and _Thread_Set_life_protection().
0011  */
0012 
0013 /*
0014  *  COPYRIGHT (c) 1989-1999.
0015  *  On-Line Applications Research Corporation (OAR).
0016  *
0017  * Copyright (C) 2014, 2022 embedded brains GmbH & Co. KG
0018  *
0019  * Redistribution and use in source and binary forms, with or without
0020  * modification, are permitted provided that the following conditions
0021  * are met:
0022  * 1. Redistributions of source code must retain the above copyright
0023  *    notice, this list of conditions and the following disclaimer.
0024  * 2. Redistributions in binary form must reproduce the above copyright
0025  *    notice, this list of conditions and the following disclaimer in the
0026  *    documentation and/or other materials provided with the distribution.
0027  *
0028  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0029  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0030  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0031  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0032  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0033  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0034  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0035  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0036  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0037  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0038  * POSSIBILITY OF SUCH DAMAGE.
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    * Add the thread to the thread zombie chain before we wake up joining
0139    * threads, so that they are able to clean up the thread immediately.  This
0140    * matters for SMP configurations.
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    * It is very unlikely that we see an executing thread here.  It can happen
0152    * in case the thread termination sequence is interrupted by a slow interrupt
0153    * service on a remote processor.
0154    */
0155   while ( _Thread_Is_executing_on_a_processor( the_thread ) ) {
0156     /* Wait */
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     /* Let other threads run */
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    * The executing thread runs with thread dispatching disabled right now.
0290    * Other threads may have suspended the executing thread.  The thread life
0291    * handler may run in parallel with _Thread_Add_life_change_request() which
0292    * may have set STATES_LIFE_IS_CHANGING.
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      * Do not remove states used for thread queues to avoid race conditions on
0353      * SMP configurations.  We could interrupt an extract operation on another
0354      * processor disregarding the thread wait flags.  Rely on
0355      * _Thread_Continue() for removal of these states.
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 }