source: rtems/cpukit/rtems/src/schedulerremoveprocessor.c @ 1ec9c86

Last change on this file since 1ec9c86 was 1ec9c86, checked in by Sebastian Huber <sebastian.huber@…>, on Jul 3, 2017 at 8:38:31 AM

rtems: Fix rtems_scheduler_remove_processor()

Account for the thread processor affinity and make sure that it is
possible to allocate a processor to each thread dedicated to a scheduler
instance.

Update #3059.

  • Property mode set to 100644
File size: 4.5 KB
Line 
1/*
2 * Copyright (c) 2016 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#if HAVE_CONFIG_H
16#include "config.h"
17#endif
18
19#include <rtems/rtems/tasks.h>
20#include <rtems/score/schedulerimpl.h>
21#include <rtems/config.h>
22
23#if defined(RTEMS_SMP)
24typedef struct {
25  const Scheduler_Control *scheduler;
26  rtems_status_code        status;
27} Scheduler_Processor_removal_context;
28
29static bool _Scheduler_Check_processor_removal(
30  Thread_Control *the_thread,
31  void           *arg
32)
33{
34  Scheduler_Processor_removal_context *iter_context;
35  Thread_queue_Context                 queue_context;
36  ISR_lock_Context                     state_context;
37
38  if ( the_thread->is_idle ) {
39    return false;
40  }
41
42  iter_context = arg;
43
44  _Thread_queue_Context_initialize( &queue_context );
45  _Thread_Wait_acquire( the_thread, &queue_context );
46  _Thread_State_acquire_critical( the_thread, &state_context );
47
48  if (
49    _Thread_Scheduler_get_home( the_thread ) == iter_context->scheduler
50      && !_Processor_mask_Has_overlap(
51        &the_thread->Scheduler.Affinity,
52        _Scheduler_Get_processors( iter_context->scheduler )
53      )
54  ) {
55    iter_context->status = RTEMS_RESOURCE_IN_USE;
56  }
57
58  _Thread_State_release_critical( the_thread, &state_context );
59  _Thread_Wait_release( the_thread, &queue_context );
60  return iter_context->status != RTEMS_SUCCESSFUL;
61}
62#endif
63
64rtems_status_code rtems_scheduler_remove_processor(
65  rtems_id scheduler_id,
66  uint32_t cpu_index
67)
68{
69  const Scheduler_Control             *scheduler;
70#if defined(RTEMS_SMP)
71  uint32_t                             processor_count;
72  Scheduler_Processor_removal_context  iter_context;
73  ISR_lock_Context                     lock_context;
74  Scheduler_Context                   *scheduler_context;
75  Per_CPU_Control                     *cpu;
76  Per_CPU_Control                     *cpu_self;
77#endif
78
79  scheduler = _Scheduler_Get_by_id( scheduler_id );
80  if ( scheduler == NULL ) {
81    return RTEMS_INVALID_ID;
82  }
83
84  if ( cpu_index >= rtems_configuration_get_maximum_processors() ) {
85    return RTEMS_INVALID_NUMBER;
86  }
87
88#if defined(RTEMS_SMP)
89  iter_context.scheduler = scheduler;
90  iter_context.status = RTEMS_SUCCESSFUL;
91  scheduler_context = _Scheduler_Get_context( scheduler );
92  cpu = _Per_CPU_Get_by_index( cpu_index );
93
94  _Objects_Allocator_lock();
95
96  if ( cpu->Scheduler.control != scheduler ) {
97    _Objects_Allocator_unlock();
98    return RTEMS_INVALID_NUMBER;
99  }
100
101  /*
102   * This prevents the selection of this scheduler instance by new threads in
103   * case the processor count changes to zero.
104   */
105  _ISR_lock_ISR_disable( &lock_context );
106  _Scheduler_Acquire_critical( scheduler, &lock_context );
107  _Processor_mask_Clear( &scheduler_context->Processors, cpu_index );
108  processor_count = _Processor_mask_Count( &scheduler_context->Processors );
109  _Scheduler_Release_critical( scheduler, &lock_context );
110  _ISR_lock_ISR_enable( &lock_context );
111
112  _Thread_Iterate( _Scheduler_Check_processor_removal, &iter_context );
113
114  _ISR_lock_ISR_disable( &lock_context );
115  _Scheduler_Acquire_critical( scheduler, &lock_context );
116
117  if ( iter_context.status == RTEMS_SUCCESSFUL ) {
118    Thread_Control *idle;
119    Scheduler_Node *scheduler_node;
120
121    cpu->Scheduler.control = NULL;
122    cpu->Scheduler.context = NULL;
123    idle = ( *scheduler->Operations.remove_processor )( scheduler, cpu );
124    cpu->Scheduler.idle_if_online_and_unused = idle;
125
126    scheduler_node = _Thread_Scheduler_get_home_node( idle );
127    _Priority_Plain_extract(
128      &scheduler_node->Wait.Priority,
129      &idle->Real_priority
130    );
131    _Assert( _Priority_Is_empty( &scheduler_node->Wait.Priority ) );
132    _Chain_Extract_unprotected( &scheduler_node->Thread.Wait_node );
133    _Assert( _Chain_Is_empty( &idle->Scheduler.Wait_nodes ) );
134    _Chain_Extract_unprotected( &scheduler_node->Thread.Scheduler_node.Chain );
135    _Assert( _Chain_Is_empty( &idle->Scheduler.Scheduler_nodes ) );
136  } else {
137    _Processor_mask_Set( &scheduler_context->Processors, cpu_index );
138  }
139
140  cpu_self = _Thread_Dispatch_disable_critical( &lock_context );
141  _Scheduler_Release_critical( scheduler, &lock_context );
142  _ISR_lock_ISR_enable( &lock_context );
143  _Thread_Dispatch_direct( cpu_self );
144  _Objects_Allocator_unlock();
145  return iter_context.status;
146#else
147  return RTEMS_RESOURCE_IN_USE;
148#endif
149}
Note: See TracBrowser for help on using the repository browser.