RTEMS
threadchangepriority.c
Go to the documentation of this file.
1 
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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include <rtems/score/threadimpl.h>
25 #include <rtems/score/assert.h>
27 
28 static void _Thread_Set_scheduler_node_priority(
29  Priority_Aggregation *priority_aggregation,
30  bool prepend_it
31 )
32 {
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)
41 static 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 
59 static 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 
78 static 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 
92 static 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)
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
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)
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
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 );
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 
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  */
233  queue_context,
234  update_count
235  );
236  }
237 }
238 
239 static 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 );
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 
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 
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 
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 
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 );
333  &scheduler_node->Wait.Priority,
334  victim_node,
335  replacement_node
336  );
337 }
338 
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)
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 );
371  the_thread,
372  sticky_level_change
373  );
374  _Thread_State_release( the_thread, &lock_context );
375 }
376 #endif
Thread_Control * owner
The thread queue owner.
Definition: threadq.h:431
The priority aggregation.
Definition: priority.h:133
const Thread_queue_Operations * operations
The current thread queue operations.
Definition: thread.h:491
static __inline__ void _Priority_Non_empty_insert(Priority_Aggregation *aggregation, Priority_Node *node, Priority_Actions *actions, Priority_Change_handler change, void *arg)
Inserts the node in a nonempty aggregation and handles change if the node is the new minimum...
Definition: priorityimpl.h:534
static __inline__ void _Priority_Set_action_type(Priority_Aggregation *aggregation, Priority_Action_type type)
Sets the action type of the priority aggregation.
Definition: priorityimpl.h:329
Thread_Wait_information Wait
Definition: thread.h:767
Thread queue context for the thread queue methods.
Definition: threadq.h:198
The priority node to build up a priority aggregation.
Definition: priority.h:98
Priority_Actions Actions
A priority action list.
Definition: threadq.h:278
Thread_Control * update[2]
Threads to update the priority via _Thread_Priority_update().
Definition: threadq.h:293
Inlined Routines Associated with the Manipulation of the Scheduler.
A list of priority actions.
Definition: priority.h:193
struct Priority_Aggregation::@17 Action
A priority action block to manage priority node additions, changes and removals.
void _Thread_Priority_and_sticky_update(Thread_Control *the_thread, int sticky_level_change)
Updates the priority of the thread and changes it sticky level.
Thread_queue_Queue * queue
The current thread queue.
Definition: thread.h:482
static __inline__ void _Thread_queue_Context_add_priority_update(Thread_queue_Context *queue_context, Thread_Control *the_thread)
Adds a priority update of the thread to the thread queue context.
Definition: threadqimpl.h:383
static __inline__ void _Priority_Insert(Priority_Aggregation *aggregation, Priority_Node *node, Priority_Actions *actions, Priority_Add_handler add, Priority_Change_handler change, void *arg)
Definition: priorityimpl.h:565
static __inline__ void _Thread_State_release(Thread_Control *the_thread, ISR_lock_Context *lock_context)
Releases the lock context and enables interrupts.
Definition: threadimpl.h:592
bool _Thread_queue_Path_acquire_critical(Thread_queue_Queue *queue, Thread_Control *the_thread, Thread_queue_Context *queue_context)
Does nothing.
Thread queue operations.
Definition: threadq.h:517
size_t update_count
Count of threads to update the priority via _Thread_Priority_update().
Definition: threadq.h:284
Information for the Assert Handler.
void _Thread_Priority_changed(Thread_Control *the_thread, Priority_Node *priority_node, bool prepend_it, Thread_queue_Context *queue_context)
Propagates a thread priority value change in the specified thread priority node to the corresponding ...
Priority_Action_type type
The type of the action.
Definition: priority.h:182
static __inline__ void _Priority_Changed(Priority_Aggregation *aggregation, Priority_Node *node, bool prepend_it, Priority_Actions *actions, Priority_Change_handler change, void *arg)
Updates the priority of the node in the aggregation.
Definition: priorityimpl.h:673
static __inline__ void _Priority_Replace(Priority_Aggregation *aggregation, Priority_Node *victim, Priority_Node *replacement)
Replaces one node by another.
Definition: priorityimpl.h:704
struct Thread_queue_Context::@31 Priority
Block to manage thread priority changes due to a thread queue operation.
static __inline__ Scheduler_Node * _Thread_Scheduler_get_home_node(const Thread_Control *the_thread)
Gets the scheduler&#39;s home node.
Definition: threadimpl.h:1438
static __inline__ Priority_Aggregation * _Priority_Actions_move(Priority_Actions *actions)
Moves the priority actions&#39; actions.
Definition: priorityimpl.h:117
static __inline__ void _Scheduler_Priority_and_sticky_update(Thread_Control *the_thread, int sticky_level_change)
Changes the sticky level of the home scheduler node and propagates a priority change of a thread to t...
Thread_queue_Priority_actions_operation priority_actions
Thread queue priority actions operation.
Definition: threadq.h:521
static __inline__ bool _Priority_Actions_is_valid(const Priority_Aggregation *aggregation)
Checks if the priority actions is valid.
Definition: priorityimpl.h:98
void _Thread_Priority_replace(Thread_Control *the_thread, Priority_Node *victim_node, Priority_Node *replacement_node)
Replaces the victim priority node with the replacement priority node in the corresponding thread prio...
static __inline__ void _Thread_queue_Context_restore_priority_updates(Thread_queue_Context *queue_context, size_t update_count)
Sets the priority update count of the thread queue context.
Definition: threadqimpl.h:367
void _Thread_Priority_update(Thread_queue_Context *queue_context)
Updates the priority of all threads in the set.
void _Thread_Priority_perform_actions(Thread_Control *start_of_path, Thread_queue_Context *queue_context)
Checks if the thread is owner of the lock of the join queue.
static __inline__ void _Priority_Extract_non_empty(Priority_Aggregation *aggregation, Priority_Node *node, Priority_Actions *actions, Priority_Change_handler change, void *arg)
Extracts the node from the aggregation.
Definition: priorityimpl.h:637
static __inline__ void _Priority_Actions_initialize_one(Priority_Actions *actions, Priority_Aggregation *aggregation, Priority_Node *node, Priority_Action_type type)
Initializes the priority actions with the given information.
Definition: priorityimpl.h:59
struct Scheduler_Node::@20 Wait
Thread wait support block.
static __inline__ void _Scheduler_Update_priority(Thread_Control *the_thread)
Propagates a priority change of a thread to the scheduler.
static __inline__ void _Scheduler_Node_set_priority(Scheduler_Node *node, Priority_Control new_priority, bool prepend_it)
Sets the priority of the node.
static __inline__ void _Priority_Actions_add(Priority_Actions *actions, Priority_Aggregation *aggregation)
Adds actions to the priority actions&#39; actions.
Definition: priorityimpl.h:135
Scheduler node for per-thread data.
Definition: schedulernode.h:79
Inlined Routines from the Thread Handler.
static __inline__ Priority_Control _Priority_Get_priority(const Priority_Aggregation *aggregation)
Gets the priority aggregation&#39;s priority.
Definition: priorityimpl.h:270
void _Thread_Priority_remove(Thread_Control *the_thread, Priority_Node *priority_node, Thread_queue_Context *queue_context)
Removes the specified thread priority node from the corresponding thread priority aggregation...
static __inline__ size_t _Thread_queue_Context_save_priority_updates(Thread_queue_Context *queue_context)
Returns the priority update count of the thread queue context.
Definition: threadqimpl.h:353
static __inline__ bool _Priority_Actions_is_empty(const Priority_Actions *actions)
Checks if the priority actions is empty.
Definition: priorityimpl.h:83
static __inline__ void _Thread_Scheduler_remove_wait_node(Thread_Control *the_thread, Scheduler_Node *scheduler_node)
Remove a wait node from the thread and add a corresponding request to it.
Definition: threadimpl.h:1585
Local ISR lock context for acquire and release pairs.
Definition: isrlock.h:65
Priority_Node * node
The priority node of the action.
Definition: priority.h:177
void _Thread_queue_Path_release_critical(Thread_queue_Context *queue_context)
Releases the thread queue path in a critical section.
Priority_Action_type
The priority action type.
Definition: priority.h:116
void _Thread_Priority_add(Thread_Control *the_thread, Priority_Node *priority_node, Thread_queue_Context *queue_context)
Adds the specified thread priority node to the corresponding thread priority aggregation.
static __inline__ void _Thread_State_acquire(Thread_Control *the_thread, ISR_lock_Context *lock_context)
Disables interrupts and acquires the lock_context.
Definition: threadimpl.h:542
static __inline__ void _Priority_Extract(Priority_Aggregation *aggregation, Priority_Node *node, Priority_Actions *actions, Priority_Remove_handler remove, Priority_Change_handler change, void *arg)
Extracts the node from the aggregation.
Definition: priorityimpl.h:599
static __inline__ Priority_Aggregation * _Priority_Get_next_action(const Priority_Aggregation *aggregation)
Gets the next action of the priority aggregation.
Definition: priorityimpl.h:363
static __inline__ void _Thread_Scheduler_add_wait_node(Thread_Control *the_thread, Scheduler_Node *scheduler_node)
Adds a wait node to the thread and adds a corresponding request to the thread.
Definition: threadimpl.h:1562
#define _Assert(_e)
Assertion similar to assert() controlled via RTEMS_DEBUG instead of NDEBUG.
Definition: assert.h:100