source: rtems/cpukit/score/src/threadchangepriority.c @ 1c2d178

5
Last change on this file since 1c2d178 was 7f742432, checked in by Sebastian Huber <sebastian.huber@…>, on 10/31/16 at 07:22:02

score: Delete Thread_Scheduler_control::own_node

Update #2556.

  • Property mode set to 100644
File size: 9.9 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  _Thread_Scheduler_add_wait_node( the_thread, scheduler_node );
54  _Thread_Set_scheduler_node_priority( priority_aggregation, false );
55  _Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_ADD );
56  _Priority_Actions_add( priority_actions, priority_aggregation );
57}
58
59static void _Thread_Priority_action_remove(
60  Priority_Aggregation *priority_aggregation,
61  Priority_Actions     *priority_actions,
62  void                 *arg
63)
64{
65  Scheduler_Node *scheduler_node;
66  Thread_Control *the_thread;
67
68  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
69  the_thread = arg;
70
71  _Thread_Scheduler_remove_wait_node( the_thread, scheduler_node );
72  _Thread_Set_scheduler_node_priority( priority_aggregation, true );
73  _Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_REMOVE );
74  _Priority_Actions_add( priority_actions, priority_aggregation );
75}
76#endif
77
78static void _Thread_Priority_action_change(
79  Priority_Aggregation *priority_aggregation,
80  bool                  prepend_it,
81  Priority_Actions     *priority_actions,
82  void                 *arg
83)
84{
85  _Thread_Set_scheduler_node_priority( priority_aggregation, prepend_it );
86#if defined(RTEMS_SMP) || defined(RTEMS_DEBUG)
87  _Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_CHANGE );
88#endif
89  _Priority_Actions_add( priority_actions, priority_aggregation );
90}
91
92static void _Thread_Priority_do_perform_actions(
93  Thread_Control                *the_thread,
94  Thread_queue_Queue            *queue,
95  const Thread_queue_Operations *operations,
96  bool                           prepend_it,
97  Thread_queue_Context          *queue_context
98)
99{
100  Priority_Aggregation *priority_aggregation;
101
102  _Assert( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) );
103  priority_aggregation = _Priority_Actions_move( &queue_context->Priority.Actions );
104
105  do {
106    Priority_Aggregation *next_aggregation;
107    Priority_Node        *priority_action_node;
108    Priority_Action_type  priority_action_type;
109
110    next_aggregation = _Priority_Get_next_action( priority_aggregation );
111
112    priority_action_node = priority_aggregation->Action.node;
113    priority_action_type = priority_aggregation->Action.type;
114
115    switch ( priority_action_type ) {
116      case PRIORITY_ACTION_ADD:
117#if defined(RTEMS_SMP)
118        _Priority_Insert(
119          priority_aggregation,
120          priority_action_node,
121          &queue_context->Priority.Actions,
122          _Thread_Priority_action_add,
123          _Thread_Priority_action_change,
124          the_thread
125        );
126#else
127        _Priority_Non_empty_insert(
128          priority_aggregation,
129          priority_action_node,
130          &queue_context->Priority.Actions,
131          _Thread_Priority_action_change,
132          NULL
133        );
134#endif
135        break;
136      case PRIORITY_ACTION_REMOVE:
137#if defined(RTEMS_SMP)
138        _Priority_Extract(
139          priority_aggregation,
140          priority_action_node,
141          &queue_context->Priority.Actions,
142          _Thread_Priority_action_remove,
143          _Thread_Priority_action_change,
144          the_thread
145        );
146#else
147        _Priority_Extract_non_empty(
148          priority_aggregation,
149          priority_action_node,
150          &queue_context->Priority.Actions,
151          _Thread_Priority_action_change,
152          NULL
153        );
154#endif
155        break;
156      default:
157        _Assert( priority_action_type == PRIORITY_ACTION_CHANGE );
158        _Priority_Changed(
159          priority_aggregation,
160          priority_action_node,
161          prepend_it,
162          &queue_context->Priority.Actions,
163          _Thread_Priority_action_change,
164          NULL
165        );
166        break;
167    }
168
169    priority_aggregation = next_aggregation;
170  } while ( _Priority_Actions_is_valid( priority_aggregation ) );
171
172  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
173    _Thread_queue_Context_add_priority_update( queue_context, the_thread );
174
175    ( *operations->priority_actions )(
176      queue,
177      &queue_context->Priority.Actions
178    );
179  }
180}
181
182void _Thread_Priority_perform_actions(
183  Thread_Control       *start_of_path,
184  Thread_queue_Context *queue_context
185)
186{
187  Thread_Control *the_thread;
188  size_t          update_count;
189
190  _Assert( start_of_path != NULL );
191
192  /*
193   * This function is tricky on SMP configurations.  Please note that we do not
194   * use the thread queue path available via the thread queue context.  Instead
195   * we directly use the thread wait information to traverse the thread queue
196   * path.  Thus, we do not necessarily acquire all thread queue locks on our
197   * own.  In case of a deadlock, we use locks acquired by other processors
198   * along the path.
199   */
200
201  the_thread = start_of_path;
202  update_count = _Thread_queue_Context_save_priority_updates( queue_context );
203
204  while ( true ) {
205    Thread_queue_Queue *queue;
206
207    queue = the_thread->Wait.queue;
208
209    _Thread_Priority_do_perform_actions(
210      the_thread,
211      queue,
212      the_thread->Wait.operations,
213      false,
214      queue_context
215    );
216
217    if ( _Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
218      return;
219    }
220
221    _Assert( queue != NULL );
222    the_thread = queue->owner;
223    _Assert( the_thread != NULL );
224
225    /*
226     * In case the priority action list is non-empty, then the current thread
227     * is enqueued on a thread queue.  There is no need to notify the scheduler
228     * about a priority change, since it will pick up the new priority once it
229     * is unblocked.  Restore the previous set of threads bound to update the
230     * priority.
231     */
232    _Thread_queue_Context_restore_priority_updates(
233      queue_context,
234      update_count
235    );
236  }
237}
238
239static void _Thread_Priority_apply(
240  Thread_Control       *the_thread,
241  Priority_Node        *priority_action_node,
242  Thread_queue_Context *queue_context,
243  bool                  prepend_it,
244  Priority_Action_type  priority_action_type
245)
246{
247  Scheduler_Node     *scheduler_node;
248  Thread_queue_Queue *queue;
249
250  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
251  _Priority_Actions_initialize_one(
252    &queue_context->Priority.Actions,
253    &scheduler_node->Wait.Priority,
254    priority_action_node,
255    priority_action_type
256  );
257  queue = the_thread->Wait.queue;
258  _Thread_Priority_do_perform_actions(
259    the_thread,
260    queue,
261    the_thread->Wait.operations,
262    prepend_it,
263    queue_context
264  );
265
266  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
267#if defined(RTEMS_SMP)
268    _Thread_queue_Path_acquire_critical( queue, the_thread, queue_context );
269#endif
270    _Thread_Priority_perform_actions( queue->owner, queue_context );
271#if defined(RTEMS_SMP)
272    _Thread_queue_Path_release_critical( queue_context );
273#endif
274  }
275}
276
277void _Thread_Priority_add(
278  Thread_Control       *the_thread,
279  Priority_Node        *priority_node,
280  Thread_queue_Context *queue_context
281)
282{
283  _Thread_Priority_apply(
284    the_thread,
285    priority_node,
286    queue_context,
287    false,
288    PRIORITY_ACTION_ADD
289  );
290}
291
292void _Thread_Priority_remove(
293  Thread_Control       *the_thread,
294  Priority_Node        *priority_node,
295  Thread_queue_Context *queue_context
296)
297{
298  _Thread_Priority_apply(
299    the_thread,
300    priority_node,
301    queue_context,
302    true,
303    PRIORITY_ACTION_REMOVE
304  );
305}
306
307void _Thread_Priority_changed(
308  Thread_Control       *the_thread,
309  Priority_Node        *priority_node,
310  bool                  prepend_it,
311  Thread_queue_Context *queue_context
312)
313{
314  _Thread_Priority_apply(
315    the_thread,
316    priority_node,
317    queue_context,
318    prepend_it,
319    PRIORITY_ACTION_CHANGE
320  );
321}
322
323void _Thread_Priority_replace(
324  Thread_Control *the_thread,
325  Priority_Node  *victim_node,
326  Priority_Node  *replacement_node
327)
328{
329  Scheduler_Node *scheduler_node;
330
331  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
332  _Priority_Replace(
333    &scheduler_node->Wait.Priority,
334    victim_node,
335    replacement_node
336  );
337}
338
339void _Thread_Priority_update( Thread_queue_Context *queue_context )
340{
341  size_t i;
342  size_t n;
343
344  n = queue_context->Priority.update_count;
345
346  /*
347   * Update the priority of all threads of the set.  Do not care to clear the
348   * set, since the thread queue context will soon get destroyed anyway.
349   */
350  for ( i = 0; i < n ; ++i ) {
351    Thread_Control   *the_thread;
352    ISR_lock_Context  lock_context;
353
354    the_thread = queue_context->Priority.update[ i ];
355    _Thread_State_acquire( the_thread, &lock_context );
356    _Scheduler_Update_priority( the_thread );
357    _Thread_State_release( the_thread, &lock_context );
358  }
359}
360
361#if defined(RTEMS_SMP)
362void _Thread_Priority_and_sticky_update(
363  Thread_Control *the_thread,
364  int             sticky_level_change
365)
366{
367  ISR_lock_Context lock_context;
368
369  _Thread_State_acquire( the_thread, &lock_context );
370  _Scheduler_Priority_and_sticky_update(
371    the_thread,
372    sticky_level_change
373  );
374  _Thread_State_release( the_thread, &lock_context );
375}
376#endif
Note: See TracBrowser for help on using the repository browser.