source: rtems/cpukit/score/src/threadchangepriority.c @ f6142c19

5
Last change on this file since f6142c19 was f6142c19, checked in by Sebastian Huber <sebastian.huber@…>, on 09/09/16 at 09:00:06

score: Scheduler node awareness for thread queues

Maintain the priority of a thread for each scheduler instance via the
thread queue enqueue, extract, priority actions and surrender
operations. This replaces the primitive priority boosting.

Update #2556.

  • Property mode set to 100644
File size: 9.5 KB
Line 
1/**
2 * @file
3 *
4 * @brief Changes the Priority of a Thread
5 *
6 * @ingroup ScoreThread
7 */
8
9/*
10 *  COPYRIGHT (c) 1989-2014.
11 *  On-Line Applications Research Corporation (OAR).
12 *
13 *  Copyright (c) 2013, 2016 embedded brains GmbH
14 *
15 *  The license and distribution terms for this file may be
16 *  found in the file LICENSE in this distribution or at
17 *  http://www.rtems.org/license/LICENSE.
18 */
19
20#if HAVE_CONFIG_H
21#include "config.h"
22#endif
23
24#include <rtems/score/threadimpl.h>
25#include <rtems/score/assert.h>
26#include <rtems/score/schedulerimpl.h>
27
28static void _Thread_Set_scheduler_node_priority(
29  Priority_Aggregation *priority_aggregation,
30  bool                  prepend_it
31)
32{
33  _Scheduler_Node_set_priority(
34    SCHEDULER_NODE_OF_WAIT_PRIORITY_NODE( priority_aggregation ),
35    _Priority_Get_priority( priority_aggregation ),
36    prepend_it
37  );
38}
39
40#if defined(RTEMS_SMP)
41static void _Thread_Priority_action_add(
42  Priority_Aggregation *priority_aggregation,
43  Priority_Actions     *priority_actions,
44  void                 *arg
45)
46{
47  Scheduler_Node *scheduler_node;
48  Thread_Control *the_thread;
49
50  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
51  the_thread = arg;
52
53  _Chain_Append_unprotected(
54    &the_thread->Scheduler.Wait_nodes,
55    &scheduler_node->Thread.Wait_node
56  );
57  _Thread_Set_scheduler_node_priority( priority_aggregation, false );
58  _Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_ADD );
59  _Priority_Actions_add( priority_actions, priority_aggregation );
60}
61
62static void _Thread_Priority_action_remove(
63  Priority_Aggregation *priority_aggregation,
64  Priority_Actions     *priority_actions,
65  void                 *arg
66)
67{
68  Scheduler_Node *scheduler_node;
69
70  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
71
72  _Chain_Extract_unprotected( &scheduler_node->Thread.Wait_node );
73  _Thread_Set_scheduler_node_priority( priority_aggregation, true );
74  _Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_REMOVE );
75  _Priority_Actions_add( priority_actions, priority_aggregation );
76}
77#endif
78
79static void _Thread_Priority_action_change(
80  Priority_Aggregation *priority_aggregation,
81  bool                  prepend_it,
82  Priority_Actions     *priority_actions,
83  void                 *arg
84)
85{
86  _Thread_Set_scheduler_node_priority( priority_aggregation, prepend_it );
87#if defined(RTEMS_SMP) || defined(RTEMS_DEBUG)
88  _Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_CHANGE );
89#endif
90  _Priority_Actions_add( priority_actions, priority_aggregation );
91}
92
93static void _Thread_Priority_do_perform_actions(
94  Thread_Control                *the_thread,
95  Thread_queue_Queue            *queue,
96  const Thread_queue_Operations *operations,
97  bool                           prepend_it,
98  Thread_queue_Context          *queue_context
99)
100{
101  Priority_Aggregation *priority_aggregation;
102
103  _Assert( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) );
104  priority_aggregation = _Priority_Actions_move( &queue_context->Priority.Actions );
105
106  do {
107    Priority_Aggregation *next_aggregation;
108    Priority_Node        *priority_action_node;
109    Priority_Action_type  priority_action_type;
110
111    next_aggregation = _Priority_Get_next_action( priority_aggregation );
112
113    priority_action_node = priority_aggregation->Action.node;
114    priority_action_type = priority_aggregation->Action.type;
115
116    switch ( priority_action_type ) {
117      case PRIORITY_ACTION_ADD:
118#if defined(RTEMS_SMP)
119        _Priority_Insert(
120          priority_aggregation,
121          priority_action_node,
122          &queue_context->Priority.Actions,
123          _Thread_Priority_action_add,
124          _Thread_Priority_action_change,
125          the_thread
126        );
127#else
128        _Priority_Non_empty_insert(
129          priority_aggregation,
130          priority_action_node,
131          &queue_context->Priority.Actions,
132          _Thread_Priority_action_change,
133          NULL
134        );
135#endif
136        break;
137      case PRIORITY_ACTION_REMOVE:
138#if defined(RTEMS_SMP)
139        _Priority_Extract(
140          priority_aggregation,
141          priority_action_node,
142          &queue_context->Priority.Actions,
143          _Thread_Priority_action_remove,
144          _Thread_Priority_action_change,
145          NULL
146        );
147#else
148        _Priority_Extract_non_empty(
149          priority_aggregation,
150          priority_action_node,
151          &queue_context->Priority.Actions,
152          _Thread_Priority_action_change,
153          NULL
154        );
155#endif
156        break;
157      default:
158        _Assert( priority_action_type == PRIORITY_ACTION_CHANGE );
159        _Priority_Changed(
160          priority_aggregation,
161          priority_action_node,
162          prepend_it,
163          &queue_context->Priority.Actions,
164          _Thread_Priority_action_change,
165          NULL
166        );
167        break;
168    }
169
170    priority_aggregation = next_aggregation;
171  } while ( _Priority_Actions_is_valid( priority_aggregation ) );
172
173  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
174    _Thread_queue_Context_add_priority_update( queue_context, the_thread );
175
176    ( *operations->priority_actions )(
177      queue,
178      &queue_context->Priority.Actions
179    );
180  }
181}
182
183void _Thread_Priority_perform_actions(
184  Thread_Control       *start_of_path,
185  Thread_queue_Context *queue_context
186)
187{
188  Thread_Control *the_thread;
189  size_t          update_count;
190
191  _Assert( start_of_path != NULL );
192
193  /*
194   * This function is tricky on SMP configurations.  Please note that we do not
195   * use the thread queue path available via the thread queue context.  Instead
196   * we directly use the thread wait information to traverse the thread queue
197   * path.  Thus, we do not necessarily acquire all thread queue locks on our
198   * own.  In case of a deadlock, we use locks acquired by other processors
199   * along the path.
200   */
201
202  the_thread = start_of_path;
203  update_count = _Thread_queue_Context_save_priority_updates( queue_context );
204
205  while ( true ) {
206    Thread_queue_Queue *queue;
207
208    queue = the_thread->Wait.queue;
209
210    _Thread_Priority_do_perform_actions(
211      the_thread,
212      queue,
213      the_thread->Wait.operations,
214      false,
215      queue_context
216    );
217
218    if ( _Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
219      return;
220    }
221
222    _Assert( queue != NULL );
223    the_thread = queue->owner;
224    _Assert( the_thread != NULL );
225
226    /*
227     * In case the priority action list is non-empty, then the current thread
228     * is enqueued on a thread queue.  There is no need to notify the scheduler
229     * about a priority change, since it will pick up the new priority once it
230     * is unblocked.  Restore the previous set of threads bound to update the
231     * priority.
232     */
233    _Thread_queue_Context_restore_priority_updates(
234      queue_context,
235      update_count
236    );
237  }
238}
239
240static void _Thread_Priority_apply(
241  Thread_Control       *the_thread,
242  Priority_Node        *priority_action_node,
243  Thread_queue_Context *queue_context,
244  bool                  prepend_it,
245  Priority_Action_type  priority_action_type
246)
247{
248  Scheduler_Node     *own_node;
249  Thread_queue_Queue *queue;
250
251  own_node = _Thread_Scheduler_get_own_node( the_thread );
252  _Priority_Actions_initialize_one(
253    &queue_context->Priority.Actions,
254    &own_node->Wait.Priority,
255    priority_action_node,
256    priority_action_type
257  );
258  queue = the_thread->Wait.queue;
259  _Thread_Priority_do_perform_actions(
260    the_thread,
261    queue,
262    the_thread->Wait.operations,
263    prepend_it,
264    queue_context
265  );
266
267  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
268#if defined(RTEMS_SMP)
269    _Thread_queue_Path_acquire_critical( queue, the_thread, queue_context );
270#endif
271    _Thread_Priority_perform_actions( queue->owner, queue_context );
272#if defined(RTEMS_SMP)
273    _Thread_queue_Path_release_critical( queue_context );
274#endif
275  }
276}
277
278void _Thread_Priority_add(
279  Thread_Control       *the_thread,
280  Priority_Node        *priority_node,
281  Thread_queue_Context *queue_context
282)
283{
284  _Thread_Priority_apply(
285    the_thread,
286    priority_node,
287    queue_context,
288    false,
289    PRIORITY_ACTION_ADD
290  );
291}
292
293void _Thread_Priority_remove(
294  Thread_Control       *the_thread,
295  Priority_Node        *priority_node,
296  Thread_queue_Context *queue_context
297)
298{
299  _Thread_Priority_apply(
300    the_thread,
301    priority_node,
302    queue_context,
303    true,
304    PRIORITY_ACTION_REMOVE
305  );
306}
307
308void _Thread_Priority_changed(
309  Thread_Control       *the_thread,
310  Priority_Node        *priority_node,
311  bool                  prepend_it,
312  Thread_queue_Context *queue_context
313)
314{
315  _Thread_Priority_apply(
316    the_thread,
317    priority_node,
318    queue_context,
319    prepend_it,
320    PRIORITY_ACTION_CHANGE
321  );
322}
323
324void _Thread_Priority_replace(
325  Thread_Control *the_thread,
326  Priority_Node  *victim_node,
327  Priority_Node  *replacement_node
328)
329{
330  Scheduler_Node *own_node;
331
332  own_node = _Thread_Scheduler_get_own_node( the_thread );
333  _Priority_Replace( &own_node->Wait.Priority, victim_node, replacement_node );
334}
335
336void _Thread_Priority_update( Thread_queue_Context *queue_context )
337{
338  size_t i;
339  size_t n;
340
341  n = queue_context->Priority.update_count;
342
343  /*
344   * Update the priority of all threads of the set.  Do not care to clear the
345   * set, since the thread queue context will soon get destroyed anyway.
346   */
347  for ( i = 0; i < n ; ++i ) {
348    Thread_Control   *the_thread;
349    ISR_lock_Context  lock_context;
350
351    the_thread = queue_context->Priority.update[ i ];
352    _Thread_State_acquire( the_thread, &lock_context );
353    _Scheduler_Update_priority( the_thread );
354    _Thread_State_release( the_thread, &lock_context );
355  }
356}
Note: See TracBrowser for help on using the repository browser.