RTEMS
threadqops.c
1 /*
2  * Copyright (c) 2015, 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 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
18 
19 #include <rtems/score/threadimpl.h>
20 #include <rtems/score/assert.h>
21 #include <rtems/score/chainimpl.h>
22 #include <rtems/score/rbtreeimpl.h>
24 
25 #define THREAD_QUEUE_CONTEXT_OF_PRIORITY_ACTIONS( priority_actions ) \
26  RTEMS_CONTAINER_OF( \
27  priority_actions, \
28  Thread_queue_Context, \
29  Priority.Actions \
30  )
31 
32 #define THREAD_QUEUE_PRIORITY_QUEUE_OF_PRIORITY_AGGREGATION( \
33  priority_aggregation \
34 ) \
35  RTEMS_CONTAINER_OF( \
36  priority_aggregation, \
37  Thread_queue_Priority_queue, \
38  Queue \
39  )
40 
41 static void _Thread_queue_Do_nothing_priority_actions(
42  Thread_queue_Queue *queue,
43  Priority_Actions *priority_actions
44 )
45 {
46  (void) queue;
47  _Priority_Actions_initialize_empty( priority_actions );
48 }
49 
50 static void _Thread_queue_Do_nothing_extract(
51  Thread_queue_Queue *queue,
52  Thread_Control *the_thread,
53  Thread_queue_Context *queue_context
54 )
55 {
56  (void) queue;
57  (void) the_thread;
58  (void) queue_context;
59 }
60 
61 static void _Thread_queue_Queue_enqueue(
62  Thread_queue_Queue *queue,
63  Thread_Control *the_thread,
64  Thread_queue_Context *queue_context,
65  void ( *initialize )(
70  ),
71  void ( *enqueue )(
76  )
77 )
78 {
79  Thread_queue_Heads *heads;
80  Thread_queue_Heads *spare_heads;
81 
82  heads = queue->heads;
83  spare_heads = the_thread->Wait.spare_heads;
84  the_thread->Wait.spare_heads = NULL;
85 
86  if ( heads == NULL ) {
87  _Assert( spare_heads != NULL );
88  _Assert( _Chain_Is_empty( &spare_heads->Free_chain ) );
89 
90  heads = spare_heads;
91  queue->heads = heads;
92  _Chain_Prepend_unprotected( &heads->Free_chain, &spare_heads->Free_node );
93  ( *initialize )( queue, the_thread, queue_context, heads );
94  } else {
95  _Chain_Prepend_unprotected( &heads->Free_chain, &spare_heads->Free_node );
96  ( *enqueue )( queue, the_thread, queue_context, heads );
97  }
98 }
99 
100 static void _Thread_queue_Queue_extract(
101  Thread_queue_Queue *queue,
102  Thread_queue_Heads *heads,
103  Thread_Control *current_or_previous_owner,
104  Thread_queue_Context *queue_context,
105  Thread_Control *the_thread,
106  void ( *extract )(
109  Thread_Control *,
112  )
113 )
114 {
115  _Assert( heads != NULL );
116 
117  the_thread->Wait.spare_heads = RTEMS_CONTAINER_OF(
120  Free_node
121  );
122 
123  if ( _Chain_Is_empty( &heads->Free_chain ) ) {
124  queue->heads = NULL;
125  }
126 
127  ( *extract )(
128  queue,
129  heads,
130  current_or_previous_owner,
131  queue_context,
132  the_thread
133  );
134 }
135 
136 static void _Thread_queue_FIFO_do_initialize(
137  Thread_queue_Queue *queue,
138  Thread_Control *the_thread,
139  Thread_queue_Context *queue_context,
140  Thread_queue_Heads *heads
141 )
142 {
143  Scheduler_Node *scheduler_node;
144 
145  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
146 
147  _Chain_Initialize_node( &scheduler_node->Wait.Priority.Node.Node.Chain );
149  &heads->Heads.Fifo,
150  &scheduler_node->Wait.Priority.Node.Node.Chain
151  );
152 }
153 
154 static void _Thread_queue_FIFO_do_enqueue(
155  Thread_queue_Queue *queue,
156  Thread_Control *the_thread,
157  Thread_queue_Context *queue_context,
158  Thread_queue_Heads *heads
159 )
160 {
161  Scheduler_Node *scheduler_node;
162 
163  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
164 
165  _Chain_Initialize_node( &scheduler_node->Wait.Priority.Node.Node.Chain );
167  &heads->Heads.Fifo,
168  &scheduler_node->Wait.Priority.Node.Node.Chain
169  );
170 }
171 
172 static void _Thread_queue_FIFO_do_extract(
173  Thread_queue_Queue *queue,
174  Thread_queue_Heads *heads,
175  Thread_Control *current_or_previous_owner,
176  Thread_queue_Context *queue_context,
177  Thread_Control *the_thread
178 )
179 {
180  Scheduler_Node *scheduler_node;
181 
182  (void) current_or_previous_owner;
183  (void) queue_context;
184 
185  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
186 
187  _Chain_Extract_unprotected( &scheduler_node->Wait.Priority.Node.Node.Chain );
188 }
189 
190 static void _Thread_queue_FIFO_enqueue(
191  Thread_queue_Queue *queue,
192  Thread_Control *the_thread,
193  Thread_queue_Context *queue_context
194 )
195 {
196  _Thread_queue_Queue_enqueue(
197  queue,
198  the_thread,
199  queue_context,
200  _Thread_queue_FIFO_do_initialize,
201  _Thread_queue_FIFO_do_enqueue
202  );
203 }
204 
205 static void _Thread_queue_FIFO_extract(
206  Thread_queue_Queue *queue,
207  Thread_Control *the_thread,
208  Thread_queue_Context *queue_context
209 )
210 {
211  _Thread_queue_Queue_extract(
212  queue,
213  queue->heads,
214  NULL,
215  queue_context,
216  the_thread,
217  _Thread_queue_FIFO_do_extract
218  );
219 }
220 
221 static Thread_Control *_Thread_queue_FIFO_first(
222  Thread_queue_Heads *heads
223 )
224 {
225  Chain_Control *fifo;
226  Chain_Node *first;
227  Scheduler_Node *scheduler_node;
228 
229  fifo = &heads->Heads.Fifo;
230  _Assert( !_Chain_Is_empty( fifo ) );
231  first = _Chain_First( fifo );
232  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY_NODE( first );
233 
234  return _Scheduler_Node_get_owner( scheduler_node );
235 }
236 
237 static Thread_Control *_Thread_queue_FIFO_surrender(
238  Thread_queue_Queue *queue,
239  Thread_queue_Heads *heads,
240  Thread_Control *previous_owner,
241  Thread_queue_Context *queue_context
242 )
243 {
244  Thread_Control *first;
245 
246  first = _Thread_queue_FIFO_first( heads );
247  _Thread_queue_Queue_extract(
248  queue,
249  heads,
250  NULL,
251  queue_context,
252  first,
253  _Thread_queue_FIFO_do_extract
254  );
255 
256  return first;
257 }
258 
259 static size_t _Thread_queue_Scheduler_index(
260  const Scheduler_Node *scheduler_node
261 )
262 {
263 #if defined(RTEMS_SMP)
264  const Scheduler_Control *scheduler;
265 
266  scheduler = _Scheduler_Node_get_scheduler( scheduler_node );
267  return _Scheduler_Get_index( scheduler );
268 #else
269  (void) scheduler_node;
270  return 0;
271 #endif
272 }
273 
274 static Thread_queue_Priority_queue *_Thread_queue_Priority_queue_by_index(
275  Thread_queue_Heads *heads,
276  size_t scheduler_index
277 )
278 {
279 #if defined(RTEMS_SMP)
280  return &heads->Priority[ scheduler_index ];
281 #else
282  (void) scheduler_index;
283  return &heads->Heads.Priority;
284 #endif
285 }
286 
287 static Thread_queue_Priority_queue *_Thread_queue_Priority_queue(
288  Thread_queue_Heads *heads,
289  const Scheduler_Node *scheduler_node
290 )
291 {
292  return _Thread_queue_Priority_queue_by_index(
293  heads,
294  _Thread_queue_Scheduler_index( scheduler_node )
295  );
296 }
297 
298 static Chain_Node *_Thread_queue_Priority_queue_rotation(
299  Thread_queue_Heads *heads
300 )
301 {
302  Chain_Node *fifo_node;
303 
304 #if defined(RTEMS_SMP)
305  /* Ensure FIFO order with respect to the priority queues */
306  fifo_node = _Chain_First( &heads->Heads.Fifo );
307  _Chain_Extract_unprotected( fifo_node );
308  _Chain_Append_unprotected( &heads->Heads.Fifo, fifo_node );
309 #else
310  (void) heads;
311  fifo_node = NULL;
312 #endif
313 
314  return fifo_node;
315 }
316 
317 #if defined(RTEMS_SMP)
318 static void _Thread_queue_Priority_queue_extract(
319  Priority_Aggregation *priority_aggregation,
320  Priority_Actions *priority_actions,
321  void *arg
322 )
323 {
324  Thread_queue_Priority_queue *priority_queue;
325 
326  (void) priority_actions;
327  (void) arg;
328 
329  priority_queue = THREAD_QUEUE_PRIORITY_QUEUE_OF_PRIORITY_AGGREGATION(
330  priority_aggregation
331  );
332 
333  _Chain_Extract_unprotected( &priority_queue->Node );
334 }
335 #endif
336 
337 static void _Thread_queue_Priority_priority_actions(
338  Thread_queue_Queue *queue,
339  Priority_Actions *priority_actions
340 )
341 {
342  Thread_queue_Heads *heads;
343  Priority_Aggregation *priority_aggregation;
344 
345  heads = queue->heads;
346  _Assert( heads != NULL );
347 
348  _Assert( !_Priority_Actions_is_empty( priority_actions ) );
349  priority_aggregation = _Priority_Actions_move( priority_actions );
350 
351  do {
352  Scheduler_Node *scheduler_node;
353  Thread_queue_Priority_queue *priority_queue;
354  Priority_Action_type priority_action_type;
355 
356  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
357  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
358  priority_action_type = priority_aggregation->Action.type;
359 
360  switch ( priority_action_type ) {
361 #if defined(RTEMS_SMP)
362  case PRIORITY_ACTION_ADD:
363  if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
364  _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
365  }
366 
368  &priority_queue->Queue,
369  &scheduler_node->Wait.Priority.Node,
370  _Priority_Get_priority( &scheduler_node->Wait.Priority )
371  );
372  break;
373  case PRIORITY_ACTION_REMOVE:
375  &priority_queue->Queue,
376  &scheduler_node->Wait.Priority.Node
377  );
378 
379  if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
380  _Chain_Extract_unprotected( &priority_queue->Node );
381  }
382  break;
383 #endif
384  default:
385  _Assert( priority_action_type == PRIORITY_ACTION_CHANGE );
387  &priority_queue->Queue,
388  &scheduler_node->Wait.Priority.Node
389  );
390  break;
391  }
392 
393  priority_aggregation = _Priority_Get_next_action( priority_aggregation );
394  } while ( _Priority_Actions_is_valid( priority_aggregation ) );
395 }
396 
397 static void _Thread_queue_Priority_do_initialize(
398  Thread_queue_Queue *queue,
399  Thread_Control *the_thread,
400  Thread_queue_Context *queue_context,
401  Thread_queue_Heads *heads
402 )
403 {
404  Scheduler_Node *scheduler_node;
405  Thread_queue_Priority_queue *priority_queue;
406 #if defined(RTEMS_SMP)
407  Chain_Node *wait_node;
408  const Chain_Node *wait_tail;
409 #endif
410 
411  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
412  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
413 
415  &priority_queue->Queue,
416  &scheduler_node->Wait.Priority.Node
417  );
418 
419 #if defined(RTEMS_SMP)
420  _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
421 
422  wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
423  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
424 
425  while ( wait_node != wait_tail ) {
426  scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
427  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
428 
430  &priority_queue->Queue,
431  &scheduler_node->Wait.Priority.Node
432  );
433  _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
434 
435  wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
436  }
437 #endif
438 }
439 
440 static void _Thread_queue_Priority_do_enqueue(
441  Thread_queue_Queue *queue,
442  Thread_Control *the_thread,
443  Thread_queue_Context *queue_context,
444  Thread_queue_Heads *heads
445 )
446 {
447 #if defined(RTEMS_SMP)
448  Chain_Node *wait_node;
449  const Chain_Node *wait_tail;
450 
451  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
452  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
453 
454  do {
455  Scheduler_Node *scheduler_node;
456  Thread_queue_Priority_queue *priority_queue;
457 
458  scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
459  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
460 
461  if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
462  _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
464  &priority_queue->Queue,
465  &scheduler_node->Wait.Priority.Node
466  );
467  } else {
469  &priority_queue->Queue,
470  &scheduler_node->Wait.Priority.Node,
471  _Priority_Get_priority( &scheduler_node->Wait.Priority )
472  );
473  }
474 
475  wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
476  } while ( wait_node != wait_tail );
477 #else
478  Scheduler_Node *scheduler_node;
479  Thread_queue_Priority_queue *priority_queue;
480 
481  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
482  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
483 
485  &priority_queue->Queue,
486  &scheduler_node->Wait.Priority.Node,
487  _Priority_Get_priority( &scheduler_node->Wait.Priority )
488  );
489 #endif
490 }
491 
492 static void _Thread_queue_Priority_do_extract(
493  Thread_queue_Queue *queue,
494  Thread_queue_Heads *heads,
495  Thread_Control *current_or_previous_owner,
496  Thread_queue_Context *queue_context,
497  Thread_Control *the_thread
498 )
499 {
500 #if defined(RTEMS_SMP)
501  Chain_Node *wait_node;
502  const Chain_Node *wait_tail;
503 
504  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
505  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
506 
507  do {
508  Scheduler_Node *scheduler_node;
509  Thread_queue_Priority_queue *priority_queue;
510 
511  scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
512  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
513 
515  &priority_queue->Queue,
516  &scheduler_node->Wait.Priority.Node
517  );
518 
519  if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
520  _Chain_Extract_unprotected( &priority_queue->Node );
521  }
522 
523  wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
524  } while ( wait_node != wait_tail );
525 #else
526  Scheduler_Node *scheduler_node;
527  Thread_queue_Priority_queue *priority_queue;
528 
529  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
530  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
531 
533  &priority_queue->Queue,
534  &scheduler_node->Wait.Priority.Node
535  );
536 #endif
537 
538  (void) current_or_previous_owner;
539  (void) queue_context;
540 }
541 
542 static void _Thread_queue_Priority_do_surrender(
543  Thread_queue_Queue *queue,
544  Thread_queue_Heads *heads,
545  Thread_Control *current_or_previous_owner,
546  Thread_queue_Context *queue_context,
547  Thread_Control *the_thread
548 )
549 {
550  _Thread_queue_Priority_queue_rotation( heads );
551  _Thread_queue_Priority_do_extract(
552  queue,
553  heads,
554  current_or_previous_owner,
555  queue_context,
556  the_thread
557  );
558 }
559 
560 static void _Thread_queue_Priority_enqueue(
561  Thread_queue_Queue *queue,
562  Thread_Control *the_thread,
563  Thread_queue_Context *queue_context
564 )
565 {
566  _Thread_queue_Queue_enqueue(
567  queue,
568  the_thread,
569  queue_context,
570  _Thread_queue_Priority_do_initialize,
571  _Thread_queue_Priority_do_enqueue
572  );
573 }
574 
575 static void _Thread_queue_Priority_extract(
576  Thread_queue_Queue *queue,
577  Thread_Control *the_thread,
578  Thread_queue_Context *queue_context
579 )
580 {
581  _Thread_queue_Queue_extract(
582  queue,
583  queue->heads,
584  NULL,
585  queue_context,
586  the_thread,
587  _Thread_queue_Priority_do_extract
588  );
589 }
590 
591 static Thread_Control *_Thread_queue_Priority_first(
592  Thread_queue_Heads *heads
593 )
594 {
595  Thread_queue_Priority_queue *priority_queue;
596  Priority_Node *first;
597  Scheduler_Node *scheduler_node;
598 
599 #if defined(RTEMS_SMP)
600  _Assert( !_Chain_Is_empty( &heads->Heads.Fifo ) );
601  priority_queue = (Thread_queue_Priority_queue *)
602  _Chain_First( &heads->Heads.Fifo );
603 #else
604  priority_queue = &heads->Heads.Priority;
605 #endif
606 
607  _Assert( !_Priority_Is_empty( &priority_queue->Queue ) );
608  first = _Priority_Get_minimum_node( &priority_queue->Queue );
609  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY_NODE( first );
610 
611  return _Scheduler_Node_get_owner( scheduler_node );
612 }
613 
614 static Thread_Control *_Thread_queue_Priority_surrender(
615  Thread_queue_Queue *queue,
616  Thread_queue_Heads *heads,
617  Thread_Control *previous_owner,
618  Thread_queue_Context *queue_context
619 )
620 {
621  Thread_Control *first;
622 
623  first = _Thread_queue_Priority_first( heads );
624  _Thread_queue_Queue_extract(
625  queue,
626  heads,
627  NULL,
628  queue_context,
629  first,
630  _Thread_queue_Priority_do_surrender
631  );
632 
633  return first;
634 }
635 
636 static void _Thread_queue_Priority_inherit_do_priority_actions_action(
637  Priority_Aggregation *priority_aggregation,
638  Priority_Actions *priority_actions,
639  Scheduler_Node *scheduler_node_of_owner,
640  Priority_Action_type priority_action_type
641 )
642 {
644  &scheduler_node_of_owner->Wait.Priority,
645  &priority_aggregation->Node,
646  priority_action_type
647  );
649  priority_actions,
650  &scheduler_node_of_owner->Wait.Priority
651  );
652 }
653 
654 #if defined(RTEMS_SMP)
655 static void _Thread_queue_Priority_inherit_do_priority_actions_add(
656  Priority_Aggregation *priority_aggregation,
657  Priority_Actions *priority_actions,
658  void *arg
659 )
660 {
661  _Thread_queue_Priority_inherit_do_priority_actions_action(
662  priority_aggregation,
663  priority_actions,
664  arg,
665  PRIORITY_ACTION_ADD
666  );
667 }
668 
669 static void _Thread_queue_Priority_inherit_do_priority_actions_remove(
670  Priority_Aggregation *priority_aggregation,
671  Priority_Actions *priority_actions,
672  void *arg
673 )
674 {
675  _Thread_queue_Priority_queue_extract(
676  priority_aggregation,
677  priority_actions,
678  arg
679  );
680  _Thread_queue_Priority_inherit_do_priority_actions_action(
681  priority_aggregation,
682  priority_actions,
683  arg,
684  PRIORITY_ACTION_REMOVE
685  );
686 }
687 #endif
688 
689 static void _Thread_queue_Priority_inherit_do_priority_actions_change(
690  Priority_Aggregation *priority_aggregation,
691  bool prepend_it,
692  Priority_Actions *priority_actions,
693  void *arg
694 )
695 {
696  _Thread_queue_Priority_inherit_do_priority_actions_action(
697  priority_aggregation,
698  priority_actions,
699  arg,
700  PRIORITY_ACTION_CHANGE
701  );
702 }
703 
704 static void _Thread_queue_Priority_inherit_priority_actions(
705  Thread_queue_Queue *queue,
706  Priority_Actions *priority_actions
707 )
708 {
709  Thread_queue_Heads *heads;
710  Thread_Control *owner;
711  Priority_Aggregation *priority_aggregation;
712 
713  heads = queue->heads;
714  _Assert( heads != NULL );
715 
716  owner = queue->owner;
717  _Assert( owner != NULL );
718 
719  _Assert( !_Priority_Actions_is_empty( priority_actions ) );
720  priority_aggregation = _Priority_Actions_move( priority_actions );
721 
722  do {
723  Priority_Aggregation *next_aggregation;
724  Scheduler_Node *scheduler_node;
725  size_t scheduler_index;
726  Thread_queue_Priority_queue *priority_queue;
727  Scheduler_Node *scheduler_node_of_owner;
728  Priority_Action_type priority_action_type;
729 
730  next_aggregation = _Priority_Get_next_action( priority_aggregation );
731 
732  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
733  scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
734  priority_queue = _Thread_queue_Priority_queue_by_index(
735  heads,
736  scheduler_index
737  );
738  scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
739  owner,
740  scheduler_index
741  );
742  priority_action_type = priority_aggregation->Action.type;
743 
744  switch ( priority_action_type ) {
745 #if defined(RTEMS_SMP)
746  case PRIORITY_ACTION_ADD:
747  if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
748  _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
749  priority_queue->scheduler_node = scheduler_node_of_owner;
750  }
751 
753  &priority_queue->Queue,
754  &scheduler_node->Wait.Priority.Node,
755  priority_actions,
756  _Thread_queue_Priority_inherit_do_priority_actions_add,
757  _Thread_queue_Priority_inherit_do_priority_actions_change,
758  scheduler_node_of_owner
759  );
760  break;
761  case PRIORITY_ACTION_REMOVE:
763  &priority_queue->Queue,
764  &scheduler_node->Wait.Priority.Node,
765  priority_actions,
766  _Thread_queue_Priority_inherit_do_priority_actions_remove,
767  _Thread_queue_Priority_inherit_do_priority_actions_change,
768  scheduler_node_of_owner
769  );
770 
771  break;
772 #endif
773  default:
774  _Assert( priority_action_type == PRIORITY_ACTION_CHANGE );
776  &priority_queue->Queue,
777  &scheduler_node->Wait.Priority.Node,
778  false,
779  priority_actions,
780  _Thread_queue_Priority_inherit_do_priority_actions_change,
781  scheduler_node_of_owner
782  );
783  break;
784  }
785 
786  priority_aggregation = next_aggregation;
787  } while ( _Priority_Actions_is_valid( priority_aggregation ) );
788 }
789 
790 static void _Thread_queue_Priority_inherit_do_initialize(
791  Thread_queue_Queue *queue,
792  Thread_Control *the_thread,
793  Thread_queue_Context *queue_context,
794  Thread_queue_Heads *heads
795 )
796 {
797  Scheduler_Node *scheduler_node;
798  size_t scheduler_index;
799  Thread_queue_Priority_queue *priority_queue;
800  Thread_Control *owner;
801  Scheduler_Node *scheduler_node_of_owner;
802 #if defined(RTEMS_SMP)
803  Chain_Node *wait_node;
804  const Chain_Node *wait_tail;
805 #endif
806 
807  owner = queue->owner;
808 
809  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
810  scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
811  priority_queue = _Thread_queue_Priority_queue_by_index(
812  heads,
813  scheduler_index
814  );
815  scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
816  owner,
817  scheduler_index
818  );
819 
820  priority_queue->scheduler_node = scheduler_node_of_owner;
822  &priority_queue->Queue,
823  &scheduler_node->Wait.Priority.Node
824  );
826  &queue_context->Priority.Actions,
827  &scheduler_node_of_owner->Wait.Priority,
828  &priority_queue->Queue.Node,
829  PRIORITY_ACTION_ADD
830  );
831 
832 #if defined(RTEMS_SMP)
833  _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
834 
835  wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
836  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
837 
838  while ( wait_node != wait_tail ) {
839  scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
840  scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
841  priority_queue = _Thread_queue_Priority_queue_by_index(
842  heads,
843  scheduler_index
844  );
845  scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
846  owner,
847  scheduler_index
848  );
849 
850  _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
851  priority_queue->scheduler_node = scheduler_node_of_owner;
853  &priority_queue->Queue,
854  &scheduler_node->Wait.Priority.Node
855  );
857  &scheduler_node_of_owner->Wait.Priority,
858  &priority_queue->Queue.Node,
859  PRIORITY_ACTION_ADD
860  );
862  &queue_context->Priority.Actions,
863  &scheduler_node_of_owner->Wait.Priority
864  );
865 
866  wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
867  }
868 #endif
869 
870  _Thread_Priority_perform_actions( owner, queue_context );
871 }
872 
873 static void _Thread_queue_Priority_inherit_do_enqueue_change(
874  Priority_Aggregation *priority_aggregation,
875  bool prepend_it,
876  Priority_Actions *priority_actions,
877  void *arg
878 )
879 {
880 #if defined(RTEMS_SMP)
881  Scheduler_Node *scheduler_node_of_owner;
882 
883  scheduler_node_of_owner = arg;
884 
886  &scheduler_node_of_owner->Wait.Priority,
887  &priority_aggregation->Node,
888  PRIORITY_ACTION_CHANGE
889  );
891  priority_actions,
892  &scheduler_node_of_owner->Wait.Priority
893  );
894 #else
895  Thread_queue_Queue *queue;
896  Thread_Control *owner;
897  Scheduler_Node *scheduler_node_of_owner;
898  Thread_queue_Context *queue_context;
899 
900  queue = arg;
901  owner = queue->owner;
902  scheduler_node_of_owner = _Thread_Scheduler_get_home_node( owner );
903  queue_context = THREAD_QUEUE_CONTEXT_OF_PRIORITY_ACTIONS( priority_actions );
904 
906  &queue_context->Priority.Actions,
907  &scheduler_node_of_owner->Wait.Priority,
908  &priority_aggregation->Node,
909  PRIORITY_ACTION_CHANGE
910  );
911  _Thread_Priority_perform_actions( owner, queue_context );
912 #endif
913 }
914 
915 static void _Thread_queue_Priority_inherit_do_enqueue(
916  Thread_queue_Queue *queue,
917  Thread_Control *the_thread,
918  Thread_queue_Context *queue_context,
919  Thread_queue_Heads *heads
920 )
921 {
922 #if defined(RTEMS_SMP)
923  Thread_Control *owner;
924  Chain_Node *wait_node;
925  const Chain_Node *wait_tail;
926 
927  owner = queue->owner;
928  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
929  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
930 
932 
933  do {
934  Scheduler_Node *scheduler_node;
935  size_t scheduler_index;
936  Thread_queue_Priority_queue *priority_queue;
937  Scheduler_Node *scheduler_node_of_owner;
938 
939  scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
940  scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
941  priority_queue = _Thread_queue_Priority_queue_by_index(
942  heads,
943  scheduler_index
944  );
945  scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
946  owner,
947  scheduler_index
948  );
949 
950  if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
951  _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
952  priority_queue->scheduler_node = scheduler_node_of_owner;
954  &priority_queue->Queue,
955  &scheduler_node->Wait.Priority.Node
956  );
958  &scheduler_node_of_owner->Wait.Priority,
959  &priority_queue->Queue.Node,
960  PRIORITY_ACTION_ADD
961  );
963  &queue_context->Priority.Actions,
964  &scheduler_node_of_owner->Wait.Priority
965  );
966  } else {
968  &priority_queue->Queue,
969  &scheduler_node->Wait.Priority.Node,
970  &queue_context->Priority.Actions,
971  _Thread_queue_Priority_inherit_do_enqueue_change,
972  scheduler_node_of_owner
973  );
974  }
975 
976  wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
977  } while ( wait_node != wait_tail );
978 
979  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
980  _Thread_Priority_perform_actions( owner, queue_context );
981  }
982 #else
983  Scheduler_Node *scheduler_node;
984  Thread_queue_Priority_queue *priority_queue;
985 
986  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
987  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
988 
990  &priority_queue->Queue,
991  &scheduler_node->Wait.Priority.Node,
992  &queue_context->Priority.Actions,
993  _Thread_queue_Priority_inherit_do_enqueue_change,
994  queue
995  );
996 #endif
997 }
998 
999 static void _Thread_queue_Priority_inherit_enqueue(
1000  Thread_queue_Queue *queue,
1001  Thread_Control *the_thread,
1002  Thread_queue_Context *queue_context
1003 )
1004 {
1005  _Thread_queue_Queue_enqueue(
1006  queue,
1007  the_thread,
1008  queue_context,
1009  _Thread_queue_Priority_inherit_do_initialize,
1010  _Thread_queue_Priority_inherit_do_enqueue
1011  );
1012 }
1013 
1014 static void _Thread_queue_Priority_inherit_do_extract_action(
1015  Priority_Actions *priority_actions,
1016  void *arg,
1017  Priority_Aggregation *priority_aggregation,
1018  Priority_Action_type priority_action_type
1019 )
1020 {
1021 #if defined(RTEMS_SMP)
1022  Scheduler_Node *scheduler_node_of_owner;
1023 
1024  scheduler_node_of_owner = arg;
1025 
1027  &scheduler_node_of_owner->Wait.Priority,
1028  &priority_aggregation->Node,
1029  priority_action_type
1030  );
1032  priority_actions,
1033  &scheduler_node_of_owner->Wait.Priority
1034  );
1035 #else
1036  Thread_queue_Context *queue_context;
1037  Thread_Control *owner;
1038  Scheduler_Node *scheduler_node_of_owner;
1039 
1040  queue_context = THREAD_QUEUE_CONTEXT_OF_PRIORITY_ACTIONS( priority_actions );
1041  owner = arg;
1042  scheduler_node_of_owner = _Thread_Scheduler_get_home_node( owner );
1043 
1045  &queue_context->Priority.Actions,
1046  &scheduler_node_of_owner->Wait.Priority,
1047  &priority_aggregation->Node,
1048  priority_action_type
1049  );
1050  _Thread_Priority_perform_actions( arg, queue_context );
1051 #endif
1052 }
1053 
1054 static void _Thread_queue_Priority_inherit_do_extract_remove(
1055  Priority_Aggregation *priority_aggregation,
1056  Priority_Actions *priority_actions,
1057  void *arg
1058 )
1059 {
1060  _Thread_queue_Priority_inherit_do_extract_action(
1061  priority_actions,
1062  arg,
1063  priority_aggregation,
1064  PRIORITY_ACTION_REMOVE
1065  );
1066 }
1067 
1068 static void _Thread_queue_Priority_inherit_do_extract_change(
1069  Priority_Aggregation *priority_aggregation,
1070  bool prepend_it,
1071  Priority_Actions *priority_actions,
1072  void *arg
1073 )
1074 {
1075  _Thread_queue_Priority_inherit_do_extract_action(
1076  priority_actions,
1077  arg,
1078  priority_aggregation,
1079  PRIORITY_ACTION_CHANGE
1080  );
1081 }
1082 
1083 static void _Thread_queue_Priority_inherit_do_extract(
1084  Thread_queue_Queue *queue,
1085  Thread_queue_Heads *heads,
1086  Thread_Control *owner,
1087  Thread_queue_Context *queue_context,
1088  Thread_Control *the_thread
1089 )
1090 {
1091 #if defined(RTEMS_SMP)
1092  Chain_Node *wait_node;
1093  const Chain_Node *wait_tail;
1094 #endif
1095  Scheduler_Node *scheduler_node;
1096  Thread_queue_Priority_queue *priority_queue;
1097 
1098 #if defined(RTEMS_SMP)
1099  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
1100  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
1101 
1103 
1104  do {
1105  size_t scheduler_index;
1106  Scheduler_Node *scheduler_node_of_owner;
1107 
1108  scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
1109  scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
1110  priority_queue = _Thread_queue_Priority_queue_by_index(
1111  heads,
1112  scheduler_index
1113  );
1114  scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
1115  owner,
1116  scheduler_index
1117  );
1118 
1120  &priority_queue->Queue,
1121  &scheduler_node->Wait.Priority.Node,
1122  &queue_context->Priority.Actions,
1123  _Thread_queue_Priority_inherit_do_extract_remove,
1124  _Thread_queue_Priority_inherit_do_extract_change,
1125  scheduler_node_of_owner
1126  );
1127 
1128  if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
1129  _Chain_Extract_unprotected( &priority_queue->Node );
1130  }
1131 
1132  wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
1133  } while ( wait_node != wait_tail );
1134 
1135  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
1136  _Thread_Priority_perform_actions( owner, queue_context );
1137  }
1138 #else
1139  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
1140  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
1141 
1143  &priority_queue->Queue,
1144  &scheduler_node->Wait.Priority.Node,
1145  &queue_context->Priority.Actions,
1146  _Thread_queue_Priority_inherit_do_extract_remove,
1147  _Thread_queue_Priority_inherit_do_extract_change,
1148  owner
1149  );
1150 #endif
1151 }
1152 
1153 static void _Thread_queue_Priority_inherit_extract(
1154  Thread_queue_Queue *queue,
1155  Thread_Control *the_thread,
1156  Thread_queue_Context *queue_context
1157 )
1158 {
1159 #if defined(RTEMS_SMP)
1160  /*
1161  * We must lock the thread wait path for the complete extract operation
1162  * including the thread queue head management. Consider the following
1163  * scenario on three processors. Thread T0 owns thread queue A, thread T1
1164  * owns thread queue B and thread T2 owns thread queue C. Thread T0 waits
1165  * for B and thread T1 waits for C.
1166  *
1167  * A <-------------------------\
1168  * \ |
1169  * > T0 -> B |
1170  * \ |
1171  * > T1 -> C |
1172  * \ |
1173  * > T2 -/
1174  *
1175  * Now three things happen at the same time
1176  * - thread T0 times out,
1177  * - thread T1 times out,
1178  * - thread T2 tries to enqueue on a thread queue A.
1179  *
1180  * Thread T1 acquires thread queue lock C and waits for thread queue lock A.
1181  * Thread T2 acquires thread queue lock A and waits for thread queue lock B.
1182  * Thread T0 acquires thread queue lock B and detects a potential deadlock.
1183  * Thread T0 carries out the thread queue extraction due to the timeout and
1184  * uses the thread wait path segments acquired by thread T1 and T2. This
1185  * resolves the deadlock. Thread T1 and T2 can the complete their
1186  * operations.
1187  */
1188  _Thread_queue_Path_acquire_critical( queue, the_thread, queue_context );
1189 #endif
1190 
1191  _Thread_queue_Queue_extract(
1192  queue,
1193  queue->heads,
1194  queue->owner,
1195  queue_context,
1196  the_thread,
1197  _Thread_queue_Priority_inherit_do_extract
1198  );
1199 
1200 #if defined(RTEMS_SMP)
1201  _Thread_queue_Path_release_critical( queue_context );
1202 #endif
1203 }
1204 
1205 #if defined(RTEMS_SMP)
1206 static void _Thread_queue_Priority_inherit_do_surrender_add(
1207  Priority_Aggregation *priority_aggregation,
1208  Priority_Actions *priority_actions,
1209  void *arg
1210 )
1211 {
1212  Scheduler_Node *scheduler_node;
1213  Thread_Control *the_thread;
1214 
1215  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
1216  the_thread = arg;
1217 
1218  _Thread_Scheduler_add_wait_node( the_thread, scheduler_node );
1220  scheduler_node,
1221  _Priority_Get_priority( priority_aggregation ),
1222  false
1223  );
1224 }
1225 
1226 static void _Thread_queue_Priority_inherit_do_surrender_remove(
1227  Priority_Aggregation *priority_aggregation,
1228  Priority_Actions *priority_actions,
1229  void *arg
1230 )
1231 {
1232  Scheduler_Node *scheduler_node;
1233  Thread_Control *the_thread;
1234 
1235  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
1236  the_thread = arg;
1237 
1238  _Thread_Scheduler_remove_wait_node( the_thread, scheduler_node );
1239  _Priority_Actions_add( priority_actions, priority_aggregation );
1240 }
1241 #endif
1242 
1243 static void _Thread_queue_Priority_inherit_do_surrender_change(
1244  Priority_Aggregation *priority_aggregation,
1245  bool prepend_it,
1246  Priority_Actions *priority_actions,
1247  void *arg
1248 )
1249 {
1250 #if defined(RTEMS_SMP)
1251  _Priority_Actions_add( priority_actions, priority_aggregation );
1252 #else
1254  THREAD_QUEUE_CONTEXT_OF_PRIORITY_ACTIONS( priority_actions ),
1255  arg
1256  );
1257 #endif
1259  SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation ),
1260  _Priority_Get_priority( priority_aggregation ),
1261  prepend_it
1262  );
1263 }
1264 
1265 #if defined(RTEMS_SMP)
1266 static void _Thread_queue_Priority_inherit_do_surrender_change_2(
1267  Priority_Aggregation *priority_aggregation,
1268  bool prepend_it,
1269  Priority_Actions *priority_actions,
1270  void *arg
1271 )
1272 {
1274  SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation ),
1275  _Priority_Get_priority( priority_aggregation ),
1276  prepend_it
1277  );
1278 }
1279 #endif
1280 
1281 static void _Thread_queue_Priority_inherit_do_surrender(
1282  Thread_queue_Queue *queue,
1283  Thread_queue_Heads *heads,
1284  Thread_Control *previous_owner,
1285  Thread_queue_Context *queue_context,
1286  Thread_Control *the_thread
1287 )
1288 {
1289 #if defined(RTEMS_SMP)
1290  Chain_Node *fifo_node;
1291  const Chain_Node *fifo_head;
1292  const Chain_Node *fifo_tail;
1293  Chain_Node *wait_node;
1294  const Chain_Node *wait_tail;
1295  ISR_lock_Context lock_context;
1296 #endif
1297  Scheduler_Node *scheduler_node;
1298  Thread_queue_Priority_queue *priority_queue;
1299  Scheduler_Node *scheduler_node_of_owner;
1300 
1301 #if defined(RTEMS_SMP)
1302  /*
1303  * Remove the priority node of each priority queue from the previous owner.
1304  * If a priority changes due to this, then register it for a priority update.
1305  */
1306 
1307  fifo_node = _Thread_queue_Priority_queue_rotation( heads );
1308  fifo_head = _Chain_Immutable_head( &heads->Heads.Fifo );
1309 
1311 
1312  _Thread_Wait_acquire_default_critical( previous_owner, &lock_context );
1313 
1314  do {
1315  priority_queue = (Thread_queue_Priority_queue *) fifo_node;
1316  scheduler_node_of_owner = priority_queue->scheduler_node;
1317 
1318  _Assert( scheduler_node_of_owner->owner == previous_owner );
1319 
1321  &scheduler_node_of_owner->Wait.Priority,
1322  &priority_queue->Queue.Node,
1323  &queue_context->Priority.Actions,
1324  _Thread_queue_Priority_inherit_do_surrender_remove,
1325  _Thread_queue_Priority_inherit_do_surrender_change,
1326  previous_owner
1327  );
1328 
1329  fifo_node = _Chain_Previous( fifo_node );
1330  } while ( fifo_node != fifo_head );
1331 
1332  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
1333  /*
1334  * The previous owner performs this surrender operation. So, it is
1335  * definitely not enqueued on a thread queue. It is sufficient to notify
1336  * the scheduler about a priority update. There is no need for a
1337  * _Thread_Priority_perform_actions().
1338  */
1339  _Thread_queue_Context_add_priority_update( queue_context, previous_owner );
1340  }
1341 
1342  _Thread_Wait_release_default_critical( previous_owner, &lock_context );
1343 
1344  /*
1345  * Remove the wait node of the new owner from the corresponding priority
1346  * queue.
1347  */
1348 
1349  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
1350  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
1351 
1352  do {
1353  scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
1354  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
1355 
1357  &priority_queue->Queue,
1358  &scheduler_node->Wait.Priority.Node,
1359  NULL,
1360  _Thread_queue_Priority_queue_extract,
1362  NULL
1363  );
1364 
1365  wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
1366  } while ( wait_node != wait_tail );
1367 
1368  /* Add the priority node of the remaining priority queues to the new owner */
1369 
1370  fifo_node = _Chain_First( &heads->Heads.Fifo );
1371  fifo_tail = _Chain_Immutable_tail( &heads->Heads.Fifo );
1372 
1373  while ( fifo_node != fifo_tail ) {
1374  const Scheduler_Control *scheduler;
1375 
1376  priority_queue = (Thread_queue_Priority_queue *) fifo_node;
1377  scheduler = _Priority_Get_scheduler( &priority_queue->Queue );
1378  scheduler_node = _Thread_Scheduler_get_node_by_index(
1379  the_thread,
1380  _Scheduler_Get_index( scheduler )
1381  );
1382 
1383  priority_queue->scheduler_node = scheduler_node;
1385  &scheduler_node->Wait.Priority,
1386  &priority_queue->Queue.Node,
1387  &queue_context->Priority.Actions,
1388  _Thread_queue_Priority_inherit_do_surrender_add,
1389  _Thread_queue_Priority_inherit_do_surrender_change_2,
1390  the_thread
1391  );
1392 
1393  fifo_node = _Chain_Next( fifo_node );
1394  }
1395 #else
1396  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
1397  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
1398  scheduler_node_of_owner = priority_queue->scheduler_node;
1399 
1401  &scheduler_node_of_owner->Wait.Priority,
1402  &priority_queue->Queue.Node,
1403  &queue_context->Priority.Actions,
1404  _Thread_queue_Priority_inherit_do_surrender_change,
1405  previous_owner
1406  );
1408  &priority_queue->Queue,
1409  &scheduler_node->Wait.Priority.Node,
1410  NULL,
1413  NULL
1414  );
1415 
1416  if ( !_Priority_Is_empty( &priority_queue->Queue ) ) {
1417  priority_queue->scheduler_node = scheduler_node;
1419  &scheduler_node->Wait.Priority,
1420  &priority_queue->Queue.Node,
1421  &queue_context->Priority.Actions,
1422  _Thread_queue_Priority_inherit_do_surrender_change,
1423  the_thread
1424  );
1425  }
1426 #endif
1427 }
1428 
1429 static Thread_Control *_Thread_queue_Priority_inherit_surrender(
1430  Thread_queue_Queue *queue,
1431  Thread_queue_Heads *heads,
1432  Thread_Control *previous_owner,
1433  Thread_queue_Context *queue_context
1434 )
1435 {
1436  Thread_Control *first;
1437 
1438  first = _Thread_queue_Priority_first( heads );
1439  _Thread_queue_Queue_extract(
1440  queue,
1441  heads,
1442  previous_owner,
1443  queue_context,
1444  first,
1445  _Thread_queue_Priority_inherit_do_surrender
1446  );
1447 
1448  return first;
1449 }
1450 
1451 const Thread_queue_Operations _Thread_queue_Operations_default = {
1452  .priority_actions = _Thread_queue_Do_nothing_priority_actions,
1453  .extract = _Thread_queue_Do_nothing_extract
1454  /*
1455  * The default operations are only used in _Thread_Change_priority() and
1456  * _Thread_Timeout() and don't have a thread queue associated with them, so
1457  * the enqueue and first operations are superfluous.
1458  */
1459 };
1460 
1461 const Thread_queue_Operations _Thread_queue_Operations_FIFO = {
1462  .priority_actions = _Thread_queue_Do_nothing_priority_actions,
1463  .enqueue = _Thread_queue_FIFO_enqueue,
1464  .extract = _Thread_queue_FIFO_extract,
1465  .surrender = _Thread_queue_FIFO_surrender,
1466  .first = _Thread_queue_FIFO_first
1467 };
1468 
1469 const Thread_queue_Operations _Thread_queue_Operations_priority = {
1470  .priority_actions = _Thread_queue_Priority_priority_actions,
1471  .enqueue = _Thread_queue_Priority_enqueue,
1472  .extract = _Thread_queue_Priority_extract,
1473  .surrender = _Thread_queue_Priority_surrender,
1474  .first = _Thread_queue_Priority_first
1475 };
1476 
1477 const Thread_queue_Operations _Thread_queue_Operations_priority_inherit = {
1478  .priority_actions = _Thread_queue_Priority_inherit_priority_actions,
1479  .enqueue = _Thread_queue_Priority_inherit_enqueue,
1480  .extract = _Thread_queue_Priority_inherit_extract,
1481  .surrender = _Thread_queue_Priority_inherit_surrender,
1482  .first = _Thread_queue_Priority_first
1483 };
Thread_Control * owner
The thread queue owner.
Definition: threadq.h:431
The priority aggregation.
Definition: priority.h:133
static __inline__ Chain_Node * _Chain_First(const Chain_Control *the_chain)
Returns pointer to chain&#39;s first node.
Definition: chainimpl.h:260
static __inline__ void _Priority_Initialize_one(Priority_Aggregation *aggregation, Priority_Node *node)
Initializes the priority aggregation with the given information.
Definition: priorityimpl.h:232
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__ const Scheduler_Control * _Priority_Get_scheduler(const Priority_Aggregation *aggregation)
Gets the priority aggregation&#39;s scheduler.
Definition: priorityimpl.h:284
Thread_Wait_information Wait
Definition: thread.h:767
Thread queue context for the thread queue methods.
Definition: threadq.h:198
static __inline__ Scheduler_Node * _Thread_Scheduler_get_node_by_index(const Thread_Control *the_thread, size_t scheduler_index)
Gets the thread&#39;s scheduler node by index.
Definition: threadimpl.h:1460
The priority node to build up a priority aggregation.
Definition: priority.h:98
Priority_Actions Actions
A priority action list.
Definition: threadq.h:278
static __inline__ void _Chain_Initialize_node(Chain_Node *the_node)
Initializes a chain node.
Definition: chainimpl.h:122
Thread priority queue.
Definition: threadq.h:324
static __inline__ void _Priority_Set_action(Priority_Aggregation *aggregation, Priority_Node *node, Priority_Action_type type)
Sets the action type and action node of the priority aggregation.
Definition: priorityimpl.h:345
Inlined Routines Associated with the Manipulation of the Scheduler.
Thread_queue_Priority_queue Priority[RTEMS_ZERO_LENGTH_ARRAY]
One priority queue per scheduler instance.
Definition: threadq.h:398
A list of priority actions.
Definition: priority.h:193
static __inline__ Chain_Node * _Chain_Get_first_unprotected(Chain_Control *the_chain)
Gets the first node (unprotected).
Definition: chainimpl.h:592
Thread_Scheduler_control Scheduler
Scheduler related control.
Definition: thread.h:764
struct Priority_Aggregation::@17 Action
A priority action block to manage priority node additions, changes and removals.
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 _Priority_Plain_extract(Priority_Aggregation *aggregation, Priority_Node *node)
Extracts the priority node from the aggregation.
Definition: priorityimpl.h:433
struct Scheduler_Node::@19 Thread
Block to register and manage this scheduler node in the thread control block of the owner of this sch...
Chain_Node Node
Node to enqueue this queue in the FIFO chain of the corresponding heads structure.
Definition: threadq.h:332
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
Information for the Assert Handler.
Chain_Node Wait_node
Node to add this scheduler node to Thread_Control::Scheduler::Wait_nodes.
Thread_queue_Heads * heads
The thread queue heads.
Definition: threadq.h:426
static __inline__ Priority_Node * _Priority_Get_minimum_node(const Priority_Aggregation *aggregation)
Gets the minimum node of the priority aggregation.
Definition: priorityimpl.h:302
#define RTEMS_CONTAINER_OF(_m, _type, _member_name)
Returns the pointer to the container of a specified member pointer.
Definition: basedefs.h:550
Thread queue heads.
Definition: threadq.h:360
static __inline__ void _Chain_Append_unprotected(Chain_Control *the_chain, Chain_Node *the_node)
Appends a node (unprotected).
Definition: chainimpl.h:680
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
Chain_Control Free_chain
A chain with free thread queue heads providing the spare thread queue heads for a thread once it is d...
Definition: threadq.h:386
Priority_Aggregation Queue
The actual thread priority queue.
Definition: threadq.h:338
static __inline__ void _Chain_Prepend_unprotected(Chain_Control *the_chain, Chain_Node *the_node)
Prepends a node (unprotected).
Definition: chainimpl.h:732
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__ Chain_Node * _Chain_Next(const Chain_Node *the_node)
Returns pointer to the next node from this node.
Definition: chainimpl.h:327
static __inline__ Priority_Aggregation * _Priority_Actions_move(Priority_Actions *actions)
Moves the priority actions&#39; actions.
Definition: priorityimpl.h:117
Thread_queue_Priority_actions_operation priority_actions
Thread queue priority actions operation.
Definition: threadq.h:521
static __inline__ Thread_Control * _Scheduler_Node_get_owner(const Scheduler_Node *node)
Gets the owner of the node.
static __inline__ void _Chain_Extract_unprotected(Chain_Node *the_node)
Extracts this node (unprotected).
Definition: chainimpl.h:558
static __inline__ bool _Priority_Actions_is_valid(const Priority_Aggregation *aggregation)
Checks if the priority actions is valid.
Definition: priorityimpl.h:98
struct _Thread_Control * owner
The thread owning this node.
Chain Handler API.
Priority_Node Node
This priority node reflects the overall priority of the aggregation.
Definition: priority.h:147
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.
Inlined Routines Associated with Red-Black Trees.
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_Change_nothing(Priority_Aggregation *aggregation, bool prepend_it, Priority_Actions *actions, void *arg)
Does nothing.
Definition: priorityimpl.h:488
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
static __inline__ bool _Priority_Is_empty(const Priority_Aggregation *aggregation)
Checks if the priority aggregation is empty.
Definition: priorityimpl.h:256
static __inline__ void _Chain_Initialize_one(Chain_Control *the_chain, Chain_Node *the_node)
Initializes this chain to contain exactly the specified node.
Definition: chainimpl.h:528
struct Scheduler_Node::@20 Wait
Thread wait support block.
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__ const Scheduler_Control * _Scheduler_Node_get_scheduler(const Scheduler_Node *node)
Gets the scheduler 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
Chain_Node Free_node
A chain node to add these thread queue heads to the free chain of the thread queue heads dedicated to...
Definition: threadq.h:392
Scheduler control.
Definition: scheduler.h:264
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
struct Scheduler_Node * scheduler_node
This priority queue is added to a scheduler node of the owner in case of priority inheritance...
Definition: threadq.h:344
static __inline__ void _Thread_Wait_acquire_default_critical(Thread_Control *the_thread, ISR_lock_Context *lock_context)
Acquires the thread wait default lock inside a critical section (interrupts disabled).
Definition: threadimpl.h:1658
static __inline__ Chain_Node * _Chain_Previous(const Chain_Node *the_node)
Returns pointer to the previous node from this node.
Definition: chainimpl.h:359
static __inline__ void _Priority_Actions_initialize_empty(Priority_Actions *actions)
Initializes the priority actions empty.
Definition: priorityimpl.h:44
Chain_Control Wait_nodes
Scheduler nodes immediately available to the thread by its home scheduler and due to thread queue own...
Definition: thread.h:279
static __inline__ const Chain_Node * _Chain_Immutable_head(const Chain_Control *the_chain)
Returns pointer to immutable chain head.
Definition: chainimpl.h:211
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
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
static __inline__ void _Thread_Wait_release_default_critical(Thread_Control *the_thread, ISR_lock_Context *lock_context)
Releases the thread wait default lock inside a critical section (interrupts disabled).
Definition: threadimpl.h:1718
union Priority_Node::@16 Node
Node component for a chain or red-black tree.
static __inline__ void _Priority_Remove_nothing(Priority_Aggregation *aggregation, Priority_Actions *actions, void *arg)
Does nothing.
Definition: priorityimpl.h:510
static __inline__ bool _Chain_Is_empty(const Chain_Control *the_chain)
Checks if the chain is empty.
Definition: chainimpl.h:393
static __inline__ void _Priority_Plain_changed(Priority_Aggregation *aggregation, Priority_Node *node)
Updates the priority of the node in the aggregation.
Definition: priorityimpl.h:450
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
Chain_Control Fifo
This is the FIFO discipline list.
Definition: threadq.h:372
static __inline__ uint32_t _Scheduler_Get_index(const Scheduler_Control *scheduler)
Gets the index of the scheduler.
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
static __inline__ const Chain_Node * _Chain_Immutable_tail(const Chain_Control *the_chain)
Returns pointer to immutable chain tail.
Definition: chainimpl.h:243
#define _Assert(_e)
Assertion similar to assert() controlled via RTEMS_DEBUG instead of NDEBUG.
Definition: assert.h:100
union _Thread_queue_Heads::@32 Heads
static __inline__ bool _Priority_Plain_insert(Priority_Aggregation *aggregation, Priority_Node *node, Priority_Control priority)
Inserts the node with the given priority into the priority aggregation&#39;s contributors.
Definition: priorityimpl.h:411