Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSImplClassicScheduler
0007  *
0008  * @brief This source file contains the implementation of
0009  *   rtems_scheduler_remove_processor().
0010  */
0011 
0012 /*
0013  * Copyright (c) 2016 embedded brains GmbH & Co. KG
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 #ifdef HAVE_CONFIG_H
0038 #include "config.h"
0039 #endif
0040 
0041 #include <rtems/rtems/scheduler.h>
0042 #include <rtems/score/schedulerimpl.h>
0043 #include <rtems/config.h>
0044 
0045 #if defined(RTEMS_SMP)
0046 typedef struct {
0047   const Scheduler_Control *scheduler;
0048   rtems_status_code        status;
0049 } Scheduler_Processor_removal_context;
0050 
0051 static bool _Scheduler_Check_processor_not_required(
0052   Thread_Control *the_thread,
0053   void           *arg
0054 )
0055 {
0056   Scheduler_Processor_removal_context *iter_context;
0057   Thread_queue_Context                 queue_context;
0058   ISR_lock_Context                     state_context;
0059 
0060   if ( the_thread->is_idle ) {
0061     return false;
0062   }
0063 
0064   iter_context = arg;
0065 
0066   _Thread_queue_Context_initialize( &queue_context );
0067   _Thread_Wait_acquire( the_thread, &queue_context );
0068   _Thread_State_acquire_critical( the_thread, &state_context );
0069 
0070   if (
0071     _Thread_Scheduler_get_home( the_thread ) == iter_context->scheduler
0072       && !_Processor_mask_Has_overlap(
0073         &the_thread->Scheduler.Affinity,
0074         _Scheduler_Get_processors( iter_context->scheduler )
0075       )
0076   ) {
0077     iter_context->status = RTEMS_RESOURCE_IN_USE;
0078   }
0079 
0080   _Thread_State_release_critical( the_thread, &state_context );
0081   _Thread_Wait_release( the_thread, &queue_context );
0082   return iter_context->status != RTEMS_SUCCESSFUL;
0083 }
0084 
0085 static bool _Scheduler_Check_no_helping(
0086   Thread_Control *the_thread,
0087   void           *arg
0088 )
0089 {
0090   Scheduler_Processor_removal_context *iter_context;
0091   ISR_lock_Context                     lock_context;
0092   const Chain_Node                    *node;
0093   const Chain_Node                    *tail;
0094 
0095   if ( the_thread->is_idle ) {
0096     return false;
0097   }
0098 
0099   iter_context = arg;
0100 
0101   _Thread_State_acquire( the_thread, &lock_context );
0102   node = _Chain_Immutable_first( &the_thread->Scheduler.Scheduler_nodes );
0103   tail = _Chain_Immutable_tail( &the_thread->Scheduler.Scheduler_nodes );
0104 
0105   do {
0106     const Scheduler_Node    *scheduler_node;
0107     const Scheduler_Control *scheduler;
0108 
0109     scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node );
0110     scheduler = _Scheduler_Node_get_scheduler( scheduler_node );
0111 
0112     if ( scheduler == iter_context->scheduler ) {
0113       iter_context->status = RTEMS_RESOURCE_IN_USE;
0114       break;
0115     }
0116 
0117     node = _Chain_Immutable_next( node );
0118   } while ( node != tail );
0119 
0120   _Thread_State_release( the_thread, &lock_context );
0121   return iter_context->status != RTEMS_SUCCESSFUL;
0122 }
0123 #endif
0124 
0125 rtems_status_code rtems_scheduler_remove_processor(
0126   rtems_id scheduler_id,
0127   uint32_t cpu_index
0128 )
0129 {
0130   const Scheduler_Control             *scheduler;
0131 #if defined(RTEMS_SMP)
0132   Scheduler_Processor_removal_context  iter_context;
0133   ISR_lock_Context                     lock_context;
0134   Scheduler_Context                   *scheduler_context;
0135   Per_CPU_Control                     *cpu;
0136   Per_CPU_Control                     *cpu_self;
0137 #endif
0138 
0139   scheduler = _Scheduler_Get_by_id( scheduler_id );
0140   if ( scheduler == NULL ) {
0141     return RTEMS_INVALID_ID;
0142   }
0143 
0144   if ( cpu_index >= rtems_configuration_get_maximum_processors() ) {
0145     return RTEMS_INVALID_NUMBER;
0146   }
0147 
0148 #if defined(RTEMS_SMP)
0149   iter_context.scheduler = scheduler;
0150   iter_context.status = RTEMS_SUCCESSFUL;
0151   scheduler_context = _Scheduler_Get_context( scheduler );
0152   cpu = _Per_CPU_Get_by_index( cpu_index );
0153 
0154   _Objects_Allocator_lock();
0155 
0156   if ( cpu->Scheduler.control != scheduler ) {
0157     _Objects_Allocator_unlock();
0158     return RTEMS_INVALID_NUMBER;
0159   }
0160 
0161   /*
0162    * This prevents the selection of this scheduler instance by new threads in
0163    * case the processor count changes to zero.
0164    */
0165   _ISR_lock_ISR_disable( &lock_context );
0166   _Scheduler_Acquire_critical( scheduler, &lock_context );
0167   _Processor_mask_Clear( &scheduler_context->Processors, cpu_index );
0168   _Scheduler_Release_critical( scheduler, &lock_context );
0169   _ISR_lock_ISR_enable( &lock_context );
0170 
0171   _Thread_Iterate( _Scheduler_Check_processor_not_required, &iter_context );
0172 
0173   if (
0174     _Processor_mask_Is_zero( &scheduler_context->Processors ) &&
0175     iter_context.status == RTEMS_SUCCESSFUL
0176   ) {
0177     _Thread_Iterate( _Scheduler_Check_no_helping, &iter_context );
0178   }
0179 
0180   _ISR_lock_ISR_disable( &lock_context );
0181   _Scheduler_Acquire_critical( scheduler, &lock_context );
0182 
0183   if ( iter_context.status == RTEMS_SUCCESSFUL ) {
0184     Thread_Control *idle;
0185     Scheduler_Node *scheduler_node;
0186 
0187     cpu->Scheduler.control = NULL;
0188     cpu->Scheduler.context = NULL;
0189     idle = ( *scheduler->Operations.remove_processor )( scheduler, cpu );
0190     cpu->Scheduler.idle_if_online_and_unused = idle;
0191 
0192     scheduler_node = _Thread_Scheduler_get_home_node( idle );
0193     _Priority_Plain_extract(
0194       &scheduler_node->Wait.Priority,
0195       &idle->Real_priority
0196     );
0197     _Assert( _Priority_Is_empty( &scheduler_node->Wait.Priority ) );
0198     _Chain_Extract_unprotected( &scheduler_node->Thread.Wait_node );
0199     _Assert( _Chain_Is_empty( &idle->Scheduler.Wait_nodes ) );
0200     _Chain_Extract_unprotected( &scheduler_node->Thread.Scheduler_node.Chain );
0201     _Assert( _Chain_Is_empty( &idle->Scheduler.Scheduler_nodes ) );
0202   } else {
0203     _Processor_mask_Set( &scheduler_context->Processors, cpu_index );
0204   }
0205 
0206   cpu_self = _Thread_Dispatch_disable_critical( &lock_context );
0207   _Scheduler_Release_critical( scheduler, &lock_context );
0208   _ISR_lock_ISR_enable( &lock_context );
0209   _Thread_Dispatch_direct( cpu_self );
0210   _Objects_Allocator_unlock();
0211   return iter_context.status;
0212 #else
0213   return RTEMS_RESOURCE_IN_USE;
0214 #endif
0215 }