source: rtems/cpukit/score/src/threadqops.c @ fce900b5

5
Last change on this file since fce900b5 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: 40.6 KB
Line 
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#if 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>
23#include <rtems/score/schedulerimpl.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
41static 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
50static 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
61static void _Thread_queue_Queue_enqueue(
62  Thread_queue_Queue   *queue,
63  Thread_Control       *the_thread,
64  Thread_queue_Context *queue_context,
65  void               ( *initialize )(
66    Thread_queue_Queue *,
67    Thread_Control *,
68    Thread_queue_Context *,
69    Thread_queue_Heads *
70  ),
71  void               ( *enqueue )(
72    Thread_queue_Queue *,
73    Thread_Control *,
74    Thread_queue_Context *,
75    Thread_queue_Heads *
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
100static 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 )(
107    Thread_queue_Queue *,
108    Thread_queue_Heads *,
109    Thread_Control *,
110    Thread_queue_Context *,
111    Thread_Control *
112  )
113)
114{
115  _Assert( heads != NULL );
116
117  the_thread->Wait.spare_heads = RTEMS_CONTAINER_OF(
118    _Chain_Get_first_unprotected( &heads->Free_chain ),
119    Thread_queue_Heads,
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
136static 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 );
148  _Chain_Initialize_one(
149    &heads->Heads.Fifo,
150    &scheduler_node->Wait.Priority.Node.Node.Chain
151  );
152}
153
154static 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 );
166  _Chain_Append_unprotected(
167    &heads->Heads.Fifo,
168    &scheduler_node->Wait.Priority.Node.Node.Chain
169  );
170}
171
172static 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
190static 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
205static 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
221static 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
237static 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
259static 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
274static 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
287static 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
298static 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)
318static 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
337static 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        _Priority_Plain_insert(
364          &priority_queue->Queue,
365          &scheduler_node->Wait.Priority.Node,
366          _Priority_Get_priority( &scheduler_node->Wait.Priority )
367        );
368        break;
369      case PRIORITY_ACTION_REMOVE:
370        _Priority_Plain_extract(
371          &priority_queue->Queue,
372          &scheduler_node->Wait.Priority.Node
373        );
374        break;
375#endif
376      default:
377        _Assert( priority_action_type == PRIORITY_ACTION_CHANGE );
378        _Priority_Plain_changed(
379          &priority_queue->Queue,
380          &scheduler_node->Wait.Priority.Node
381        );
382        break;
383    }
384
385    priority_aggregation = _Priority_Get_next_action( priority_aggregation );
386  } while ( _Priority_Actions_is_valid( priority_aggregation ) );
387}
388
389static void _Thread_queue_Priority_do_initialize(
390  Thread_queue_Queue   *queue,
391  Thread_Control       *the_thread,
392  Thread_queue_Context *queue_context,
393  Thread_queue_Heads   *heads
394)
395{
396  Scheduler_Node              *scheduler_node;
397  Thread_queue_Priority_queue *priority_queue;
398#if defined(RTEMS_SMP)
399  Chain_Node                  *wait_node;
400  const Chain_Node            *wait_tail;
401#endif
402
403  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
404  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
405
406  _Priority_Initialize_one(
407    &priority_queue->Queue,
408    &scheduler_node->Wait.Priority.Node
409  );
410
411#if defined(RTEMS_SMP)
412  _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
413
414  wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
415  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
416
417  while ( wait_node != wait_tail ) {
418    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
419    priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
420
421    _Priority_Initialize_one(
422      &priority_queue->Queue,
423      &scheduler_node->Wait.Priority.Node
424    );
425    _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
426
427    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
428  }
429#endif
430}
431
432static void _Thread_queue_Priority_do_enqueue(
433  Thread_queue_Queue   *queue,
434  Thread_Control       *the_thread,
435  Thread_queue_Context *queue_context,
436  Thread_queue_Heads   *heads
437)
438{
439#if defined(RTEMS_SMP)
440  Chain_Node       *wait_node;
441  const Chain_Node *wait_tail;
442
443  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
444  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
445
446  do {
447    Scheduler_Node              *scheduler_node;
448    Thread_queue_Priority_queue *priority_queue;
449
450    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
451    priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
452
453    if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
454      _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
455      _Priority_Initialize_one(
456        &priority_queue->Queue,
457        &scheduler_node->Wait.Priority.Node
458      );
459    } else {
460      _Priority_Plain_insert(
461        &priority_queue->Queue,
462        &scheduler_node->Wait.Priority.Node,
463        _Priority_Get_priority( &scheduler_node->Wait.Priority )
464      );
465    }
466
467    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
468  } while ( wait_node != wait_tail );
469#else
470  Scheduler_Node              *scheduler_node;
471  Thread_queue_Priority_queue *priority_queue;
472
473  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
474  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
475
476  _Priority_Plain_insert(
477    &priority_queue->Queue,
478    &scheduler_node->Wait.Priority.Node,
479    _Priority_Get_priority( &scheduler_node->Wait.Priority )
480  );
481#endif
482}
483
484static void _Thread_queue_Priority_do_extract(
485  Thread_queue_Queue   *queue,
486  Thread_queue_Heads   *heads,
487  Thread_Control       *current_or_previous_owner,
488  Thread_queue_Context *queue_context,
489  Thread_Control       *the_thread
490)
491{
492#if defined(RTEMS_SMP)
493  Chain_Node       *wait_node;
494  const Chain_Node *wait_tail;
495
496  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
497  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
498
499  do {
500    Scheduler_Node              *scheduler_node;
501    Thread_queue_Priority_queue *priority_queue;
502
503    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
504    priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
505
506    _Priority_Plain_extract(
507      &priority_queue->Queue,
508      &scheduler_node->Wait.Priority.Node
509    );
510
511    if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
512      _Chain_Extract_unprotected( &priority_queue->Node );
513    }
514
515    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
516  } while ( wait_node != wait_tail );
517#else
518  Scheduler_Node              *scheduler_node;
519  Thread_queue_Priority_queue *priority_queue;
520
521  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
522  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
523
524  _Priority_Plain_extract(
525    &priority_queue->Queue,
526    &scheduler_node->Wait.Priority.Node
527  );
528#endif
529
530  (void) current_or_previous_owner;
531  (void) queue_context;
532}
533
534static void _Thread_queue_Priority_do_surrender(
535  Thread_queue_Queue   *queue,
536  Thread_queue_Heads   *heads,
537  Thread_Control       *current_or_previous_owner,
538  Thread_queue_Context *queue_context,
539  Thread_Control       *the_thread
540)
541{
542  _Thread_queue_Priority_queue_rotation( heads );
543  _Thread_queue_Priority_do_extract(
544    queue,
545    heads,
546    current_or_previous_owner,
547    queue_context,
548    the_thread
549  );
550}
551
552static void _Thread_queue_Priority_enqueue(
553  Thread_queue_Queue   *queue,
554  Thread_Control       *the_thread,
555  Thread_queue_Context *queue_context
556)
557{
558  _Thread_queue_Queue_enqueue(
559    queue,
560    the_thread,
561    queue_context,
562    _Thread_queue_Priority_do_initialize,
563    _Thread_queue_Priority_do_enqueue
564  );
565}
566
567static void _Thread_queue_Priority_extract(
568  Thread_queue_Queue   *queue,
569  Thread_Control       *the_thread,
570  Thread_queue_Context *queue_context
571)
572{
573  _Thread_queue_Queue_extract(
574    queue,
575    queue->heads,
576    NULL,
577    queue_context,
578    the_thread,
579    _Thread_queue_Priority_do_extract
580  );
581}
582
583static Thread_Control *_Thread_queue_Priority_first(
584  Thread_queue_Heads *heads
585)
586{
587  Thread_queue_Priority_queue *priority_queue;
588  Priority_Node               *first;
589  Scheduler_Node              *scheduler_node;
590
591#if defined(RTEMS_SMP)
592  _Assert( !_Chain_Is_empty( &heads->Heads.Fifo ) );
593  priority_queue = (Thread_queue_Priority_queue *)
594    _Chain_First( &heads->Heads.Fifo );
595#else
596  priority_queue = &heads->Heads.Priority;
597#endif
598
599  _Assert( !_Priority_Is_empty( &priority_queue->Queue ) );
600  first = _Priority_Get_minimum_node( &priority_queue->Queue );
601  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY_NODE( first );
602
603  return _Scheduler_Node_get_owner( scheduler_node );
604}
605
606static Thread_Control *_Thread_queue_Priority_surrender(
607  Thread_queue_Queue   *queue,
608  Thread_queue_Heads   *heads,
609  Thread_Control       *previous_owner,
610  Thread_queue_Context *queue_context
611)
612{
613  Thread_Control *first;
614
615  first = _Thread_queue_Priority_first( heads );
616  _Thread_queue_Queue_extract(
617    queue,
618    heads,
619    NULL,
620    queue_context,
621    first,
622    _Thread_queue_Priority_do_surrender
623  );
624
625  return first;
626}
627
628static void _Thread_queue_Priority_inherit_do_priority_actions_action(
629  Priority_Aggregation *priority_aggregation,
630  Priority_Actions     *priority_actions,
631  Scheduler_Node       *scheduler_node_of_owner,
632  Priority_Action_type  priority_action_type
633)
634{
635  _Priority_Set_action(
636    &scheduler_node_of_owner->Wait.Priority,
637    &priority_aggregation->Node,
638    priority_action_type
639  );
640  _Priority_Actions_add(
641    priority_actions,
642    &scheduler_node_of_owner->Wait.Priority
643  );
644}
645
646#if defined(RTEMS_SMP)
647static void _Thread_queue_Priority_inherit_do_priority_actions_add(
648  Priority_Aggregation *priority_aggregation,
649  Priority_Actions     *priority_actions,
650  void                 *arg
651)
652{
653  _Thread_queue_Priority_inherit_do_priority_actions_action(
654    priority_aggregation,
655    priority_actions,
656    arg,
657    PRIORITY_ACTION_ADD
658  );
659}
660
661static void _Thread_queue_Priority_inherit_do_priority_actions_remove(
662  Priority_Aggregation *priority_aggregation,
663  Priority_Actions     *priority_actions,
664  void                 *arg
665)
666{
667  _Thread_queue_Priority_queue_extract(
668    priority_aggregation,
669    priority_actions,
670    arg
671  );
672  _Thread_queue_Priority_inherit_do_priority_actions_action(
673    priority_aggregation,
674    priority_actions,
675    arg,
676    PRIORITY_ACTION_REMOVE
677  );
678}
679#endif
680
681static void _Thread_queue_Priority_inherit_do_priority_actions_change(
682  Priority_Aggregation *priority_aggregation,
683  bool                  prepend_it,
684  Priority_Actions     *priority_actions,
685  void                 *arg
686)
687{
688  _Thread_queue_Priority_inherit_do_priority_actions_action(
689    priority_aggregation,
690    priority_actions,
691    arg,
692    PRIORITY_ACTION_CHANGE
693  );
694}
695
696static void _Thread_queue_Priority_inherit_priority_actions(
697  Thread_queue_Queue *queue,
698  Priority_Actions   *priority_actions
699)
700{
701  Thread_queue_Heads   *heads;
702  Thread_Control       *owner;
703  Priority_Aggregation *priority_aggregation;
704
705  heads = queue->heads;
706  _Assert( heads != NULL );
707
708  owner = queue->owner;
709  _Assert( owner != NULL );
710
711  _Assert( !_Priority_Actions_is_empty( priority_actions ) );
712  priority_aggregation = _Priority_Actions_move( priority_actions );
713
714  do {
715    Priority_Aggregation        *next_aggregation;
716    Scheduler_Node              *scheduler_node;
717    size_t                       scheduler_index;
718    Thread_queue_Priority_queue *priority_queue;
719    Scheduler_Node              *scheduler_node_of_owner;
720    Priority_Action_type         priority_action_type;
721
722    next_aggregation = _Priority_Get_next_action( priority_aggregation );
723
724    scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
725    scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
726    priority_queue = _Thread_queue_Priority_queue_by_index(
727      heads,
728      scheduler_index
729    );
730    scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
731      owner,
732      scheduler_index
733    );
734    priority_action_type = priority_aggregation->Action.type;
735
736    switch ( priority_action_type ) {
737#if defined(RTEMS_SMP)
738      case PRIORITY_ACTION_ADD:
739        if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
740          _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
741          priority_queue->scheduler_node = scheduler_node_of_owner;
742        }
743
744        _Priority_Insert(
745          &priority_queue->Queue,
746          &scheduler_node->Wait.Priority.Node,
747          priority_actions,
748          _Thread_queue_Priority_inherit_do_priority_actions_add,
749          _Thread_queue_Priority_inherit_do_priority_actions_change,
750          scheduler_node_of_owner
751        );
752        break;
753      case PRIORITY_ACTION_REMOVE:
754        _Priority_Extract(
755          &priority_queue->Queue,
756          &scheduler_node->Wait.Priority.Node,
757          priority_actions,
758          _Thread_queue_Priority_inherit_do_priority_actions_remove,
759          _Thread_queue_Priority_inherit_do_priority_actions_change,
760          scheduler_node_of_owner
761        );
762
763        break;
764#endif
765      default:
766        _Assert( priority_action_type == PRIORITY_ACTION_CHANGE );
767        _Priority_Changed(
768          &priority_queue->Queue,
769          &scheduler_node->Wait.Priority.Node,
770          false,
771          priority_actions,
772          _Thread_queue_Priority_inherit_do_priority_actions_change,
773          scheduler_node_of_owner
774        );
775        break;
776    }
777
778    priority_aggregation = next_aggregation;
779  } while ( _Priority_Actions_is_valid( priority_aggregation ) );
780}
781
782static void _Thread_queue_Priority_inherit_do_initialize(
783  Thread_queue_Queue   *queue,
784  Thread_Control       *the_thread,
785  Thread_queue_Context *queue_context,
786  Thread_queue_Heads   *heads
787)
788{
789  Scheduler_Node              *scheduler_node;
790  size_t                       scheduler_index;
791  Thread_queue_Priority_queue *priority_queue;
792  Thread_Control              *owner;
793  Scheduler_Node              *scheduler_node_of_owner;
794#if defined(RTEMS_SMP)
795  Chain_Node                  *wait_node;
796  const Chain_Node            *wait_tail;
797#endif
798
799  owner = queue->owner;
800
801  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
802  scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
803  priority_queue = _Thread_queue_Priority_queue_by_index(
804    heads,
805    scheduler_index
806  );
807  scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
808    owner,
809    scheduler_index
810  );
811
812  priority_queue->scheduler_node = scheduler_node_of_owner;
813  _Priority_Initialize_one(
814    &priority_queue->Queue,
815    &scheduler_node->Wait.Priority.Node
816  );
817  _Priority_Actions_initialize_one(
818    &queue_context->Priority.Actions,
819    &scheduler_node_of_owner->Wait.Priority,
820    &priority_queue->Queue.Node,
821    PRIORITY_ACTION_ADD
822  );
823
824#if defined(RTEMS_SMP)
825  _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
826
827  wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
828  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
829
830  while ( wait_node != wait_tail ) {
831    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
832    scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
833    priority_queue = _Thread_queue_Priority_queue_by_index(
834      heads,
835      scheduler_index
836    );
837    scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
838      owner,
839      scheduler_index
840    );
841
842    _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
843    priority_queue->scheduler_node = scheduler_node_of_owner;
844    _Priority_Initialize_one(
845      &priority_queue->Queue,
846      &scheduler_node->Wait.Priority.Node
847    );
848    _Priority_Set_action(
849      &scheduler_node_of_owner->Wait.Priority,
850      &priority_queue->Queue.Node,
851      PRIORITY_ACTION_ADD
852    );
853    _Priority_Actions_add(
854      &queue_context->Priority.Actions,
855      &scheduler_node_of_owner->Wait.Priority
856    );
857
858    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
859  }
860#endif
861
862  _Thread_Priority_perform_actions( owner, queue_context );
863}
864
865static void _Thread_queue_Priority_inherit_do_enqueue_change(
866  Priority_Aggregation *priority_aggregation,
867  bool                  prepend_it,
868  Priority_Actions     *priority_actions,
869  void                 *arg
870)
871{
872#if defined(RTEMS_SMP)
873  Scheduler_Node *scheduler_node_of_owner;
874
875  scheduler_node_of_owner = arg;
876
877  _Priority_Set_action(
878    &scheduler_node_of_owner->Wait.Priority,
879    &priority_aggregation->Node,
880    PRIORITY_ACTION_CHANGE
881  );
882  _Priority_Actions_add(
883    priority_actions,
884    &scheduler_node_of_owner->Wait.Priority
885  );
886#else
887  Thread_queue_Queue   *queue;
888  Thread_Control       *owner;
889  Scheduler_Node       *scheduler_node_of_owner;
890  Thread_queue_Context *queue_context;
891
892  queue = arg;
893  owner = queue->owner;
894  scheduler_node_of_owner = _Thread_Scheduler_get_home_node( owner );
895  queue_context = THREAD_QUEUE_CONTEXT_OF_PRIORITY_ACTIONS( priority_actions );
896
897  _Priority_Actions_initialize_one(
898    &queue_context->Priority.Actions,
899    &scheduler_node_of_owner->Wait.Priority,
900    &priority_aggregation->Node,
901    PRIORITY_ACTION_CHANGE
902  );
903  _Thread_Priority_perform_actions( owner, queue_context );
904#endif
905}
906
907static void _Thread_queue_Priority_inherit_do_enqueue(
908  Thread_queue_Queue   *queue,
909  Thread_Control       *the_thread,
910  Thread_queue_Context *queue_context,
911  Thread_queue_Heads   *heads
912)
913{
914#if defined(RTEMS_SMP)
915  Thread_Control   *owner;
916  Chain_Node       *wait_node;
917  const Chain_Node *wait_tail;
918
919  owner = queue->owner;
920  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
921  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
922
923  _Priority_Actions_initialize_empty( &queue_context->Priority.Actions );
924
925  do {
926    Scheduler_Node              *scheduler_node;
927    size_t                       scheduler_index;
928    Thread_queue_Priority_queue *priority_queue;
929    Scheduler_Node              *scheduler_node_of_owner;
930
931    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
932    scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
933    priority_queue = _Thread_queue_Priority_queue_by_index(
934      heads,
935      scheduler_index
936    );
937    scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
938      owner,
939      scheduler_index
940    );
941
942    if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
943      _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
944      priority_queue->scheduler_node = scheduler_node_of_owner;
945      _Priority_Initialize_one(
946        &priority_queue->Queue,
947        &scheduler_node->Wait.Priority.Node
948      );
949      _Priority_Set_action(
950        &scheduler_node_of_owner->Wait.Priority,
951        &priority_queue->Queue.Node,
952        PRIORITY_ACTION_ADD
953      );
954      _Priority_Actions_add(
955        &queue_context->Priority.Actions,
956        &scheduler_node_of_owner->Wait.Priority
957      );
958    } else {
959      _Priority_Non_empty_insert(
960        &priority_queue->Queue,
961        &scheduler_node->Wait.Priority.Node,
962        &queue_context->Priority.Actions,
963        _Thread_queue_Priority_inherit_do_enqueue_change,
964        scheduler_node_of_owner
965      );
966    }
967
968    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
969  } while ( wait_node != wait_tail );
970
971  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
972    _Thread_Priority_perform_actions( owner, queue_context );
973  }
974#else
975  Scheduler_Node              *scheduler_node;
976  Thread_queue_Priority_queue *priority_queue;
977
978  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
979  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
980
981  _Priority_Non_empty_insert(
982    &priority_queue->Queue,
983    &scheduler_node->Wait.Priority.Node,
984    &queue_context->Priority.Actions,
985    _Thread_queue_Priority_inherit_do_enqueue_change,
986    queue
987  );
988#endif
989}
990
991static void _Thread_queue_Priority_inherit_enqueue(
992  Thread_queue_Queue   *queue,
993  Thread_Control       *the_thread,
994  Thread_queue_Context *queue_context
995)
996{
997  _Thread_queue_Queue_enqueue(
998    queue,
999    the_thread,
1000    queue_context,
1001    _Thread_queue_Priority_inherit_do_initialize,
1002    _Thread_queue_Priority_inherit_do_enqueue
1003  );
1004}
1005
1006static void _Thread_queue_Priority_inherit_do_extract_action(
1007  Priority_Actions     *priority_actions,
1008  void                 *arg,
1009  Priority_Aggregation *priority_aggregation,
1010  Priority_Action_type  priority_action_type
1011)
1012{
1013#if defined(RTEMS_SMP)
1014  Scheduler_Node *scheduler_node_of_owner;
1015
1016  scheduler_node_of_owner = arg;
1017
1018  _Priority_Set_action(
1019    &scheduler_node_of_owner->Wait.Priority,
1020    &priority_aggregation->Node,
1021    priority_action_type
1022  );
1023  _Priority_Actions_add(
1024    priority_actions,
1025    &scheduler_node_of_owner->Wait.Priority
1026  );
1027#else
1028  Thread_queue_Context *queue_context;
1029  Thread_Control       *owner;
1030  Scheduler_Node       *scheduler_node_of_owner;
1031
1032  queue_context = THREAD_QUEUE_CONTEXT_OF_PRIORITY_ACTIONS( priority_actions );
1033  owner = arg;
1034  scheduler_node_of_owner = _Thread_Scheduler_get_home_node( owner );
1035
1036  _Priority_Actions_initialize_one(
1037    &queue_context->Priority.Actions,
1038    &scheduler_node_of_owner->Wait.Priority,
1039    &priority_aggregation->Node,
1040    priority_action_type
1041  );
1042  _Thread_Priority_perform_actions( arg, queue_context );
1043#endif
1044}
1045
1046static void _Thread_queue_Priority_inherit_do_extract_remove(
1047  Priority_Aggregation *priority_aggregation,
1048  Priority_Actions     *priority_actions,
1049  void                 *arg
1050)
1051{
1052  _Thread_queue_Priority_inherit_do_extract_action(
1053    priority_actions,
1054    arg,
1055    priority_aggregation,
1056    PRIORITY_ACTION_REMOVE
1057  );
1058}
1059
1060static void _Thread_queue_Priority_inherit_do_extract_change(
1061  Priority_Aggregation *priority_aggregation,
1062  bool                  prepend_it,
1063  Priority_Actions     *priority_actions,
1064  void                 *arg
1065)
1066{
1067  _Thread_queue_Priority_inherit_do_extract_action(
1068    priority_actions,
1069    arg,
1070    priority_aggregation,
1071    PRIORITY_ACTION_CHANGE
1072  );
1073}
1074
1075static void _Thread_queue_Priority_inherit_do_extract(
1076  Thread_queue_Queue   *queue,
1077  Thread_queue_Heads   *heads,
1078  Thread_Control       *owner,
1079  Thread_queue_Context *queue_context,
1080  Thread_Control       *the_thread
1081)
1082{
1083#if defined(RTEMS_SMP)
1084  Chain_Node                  *wait_node;
1085  const Chain_Node            *wait_tail;
1086#endif
1087  Scheduler_Node              *scheduler_node;
1088  Thread_queue_Priority_queue *priority_queue;
1089
1090#if defined(RTEMS_SMP)
1091  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
1092  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
1093
1094  _Priority_Actions_initialize_empty( &queue_context->Priority.Actions );
1095
1096  do {
1097    size_t          scheduler_index;
1098    Scheduler_Node *scheduler_node_of_owner;
1099
1100    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
1101    scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
1102    priority_queue = _Thread_queue_Priority_queue_by_index(
1103      heads,
1104      scheduler_index
1105    );
1106    scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
1107      owner,
1108      scheduler_index
1109    );
1110
1111    _Priority_Extract(
1112      &priority_queue->Queue,
1113      &scheduler_node->Wait.Priority.Node,
1114      &queue_context->Priority.Actions,
1115      _Thread_queue_Priority_inherit_do_extract_remove,
1116      _Thread_queue_Priority_inherit_do_extract_change,
1117      scheduler_node_of_owner
1118    );
1119
1120    if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
1121      _Chain_Extract_unprotected( &priority_queue->Node );
1122    }
1123
1124    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
1125  } while ( wait_node != wait_tail );
1126
1127  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
1128    _Thread_Priority_perform_actions( owner, queue_context );
1129  }
1130#else
1131  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
1132  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
1133
1134  _Priority_Extract(
1135    &priority_queue->Queue,
1136    &scheduler_node->Wait.Priority.Node,
1137    &queue_context->Priority.Actions,
1138    _Thread_queue_Priority_inherit_do_extract_remove,
1139    _Thread_queue_Priority_inherit_do_extract_change,
1140    owner
1141  );
1142#endif
1143}
1144
1145static void _Thread_queue_Priority_inherit_extract(
1146  Thread_queue_Queue   *queue,
1147  Thread_Control       *the_thread,
1148  Thread_queue_Context *queue_context
1149)
1150{
1151#if defined(RTEMS_SMP)
1152  /*
1153   * We must lock the thread wait path for the complete extract operation
1154   * including the thread queue head management.  Consider the following
1155   * scenario on three processors.  Thread T0 owns thread queue A, thread T1
1156   * owns thread queue B and thread T2 owns thread queue C.  Thread T0 waits
1157   * for B and thread T1 waits for C.
1158   *
1159   * A <-------------------------\
1160   *  \                          |
1161   *   > T0 -> B                 |
1162   *            \                |
1163   *             > T1 -> C       |
1164   *                      \      |
1165   *                       > T2 -/
1166   *
1167   * Now three things happen at the same time
1168   *  - thread T0 times out,
1169   *  - thread T1 times out,
1170   *  - thread T2 tries to enqueue on a thread queue A.
1171   *
1172   * Thread T1 acquires thread queue lock C and waits for thread queue lock A.
1173   * Thread T2 acquires thread queue lock A and waits for thread queue lock B.
1174   * Thread T0 acquires thread queue lock B and detects a potential deadlock.
1175   * Thread T0 carries out the thread queue extraction due to the timeout and
1176   * uses the thread wait path segments acquired by thread T1 and T2.  This
1177   * resolves the deadlock.  Thread T1 and T2 can the complete their
1178   * operations.
1179   */
1180  _Thread_queue_Path_acquire_critical( queue, the_thread, queue_context );
1181#endif
1182
1183  _Thread_queue_Queue_extract(
1184    queue,
1185    queue->heads,
1186    queue->owner,
1187    queue_context,
1188    the_thread,
1189    _Thread_queue_Priority_inherit_do_extract
1190  );
1191
1192#if defined(RTEMS_SMP)
1193  _Thread_queue_Path_release_critical( queue_context );
1194#endif
1195}
1196
1197#if defined(RTEMS_SMP)
1198static void _Thread_queue_Priority_inherit_do_surrender_add(
1199  Priority_Aggregation *priority_aggregation,
1200  Priority_Actions     *priority_actions,
1201  void                 *arg
1202)
1203{
1204  Scheduler_Node *scheduler_node;
1205  Thread_Control *the_thread;
1206
1207  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
1208  the_thread = arg;
1209
1210  _Thread_Scheduler_add_wait_node( the_thread, scheduler_node );
1211  _Scheduler_Node_set_priority(
1212    scheduler_node,
1213    _Priority_Get_priority( priority_aggregation ),
1214    false
1215  );
1216}
1217
1218static void _Thread_queue_Priority_inherit_do_surrender_remove(
1219  Priority_Aggregation *priority_aggregation,
1220  Priority_Actions     *priority_actions,
1221  void                 *arg
1222)
1223{
1224  Scheduler_Node *scheduler_node;
1225  Thread_Control *the_thread;
1226
1227  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
1228  the_thread = arg;
1229
1230  _Thread_Scheduler_remove_wait_node( the_thread, scheduler_node );
1231  _Priority_Actions_add( priority_actions, priority_aggregation );
1232}
1233#endif
1234
1235static void _Thread_queue_Priority_inherit_do_surrender_change(
1236  Priority_Aggregation *priority_aggregation,
1237  bool                  prepend_it,
1238  Priority_Actions     *priority_actions,
1239  void                 *arg
1240)
1241{
1242#if defined(RTEMS_SMP)
1243  _Priority_Actions_add( priority_actions, priority_aggregation );
1244#else
1245  _Thread_queue_Context_add_priority_update(
1246    THREAD_QUEUE_CONTEXT_OF_PRIORITY_ACTIONS( priority_actions ),
1247    arg
1248  );
1249#endif
1250  _Scheduler_Node_set_priority(
1251    SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation ),
1252    _Priority_Get_priority( priority_aggregation ),
1253    prepend_it
1254  );
1255}
1256
1257#if defined(RTEMS_SMP)
1258static void _Thread_queue_Priority_inherit_do_surrender_change_2(
1259  Priority_Aggregation *priority_aggregation,
1260  bool                  prepend_it,
1261  Priority_Actions     *priority_actions,
1262  void                 *arg
1263)
1264{
1265  _Scheduler_Node_set_priority(
1266    SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation ),
1267    _Priority_Get_priority( priority_aggregation ),
1268    prepend_it
1269  );
1270}
1271#endif
1272
1273static void _Thread_queue_Priority_inherit_do_surrender(
1274  Thread_queue_Queue   *queue,
1275  Thread_queue_Heads   *heads,
1276  Thread_Control       *previous_owner,
1277  Thread_queue_Context *queue_context,
1278  Thread_Control       *the_thread
1279)
1280{
1281#if defined(RTEMS_SMP)
1282  Chain_Node                  *fifo_node;
1283  const Chain_Node            *fifo_head;
1284  const Chain_Node            *fifo_tail;
1285  Chain_Node                  *wait_node;
1286  const Chain_Node            *wait_tail;
1287  ISR_lock_Context             lock_context;
1288#endif
1289  Scheduler_Node              *scheduler_node;
1290  Thread_queue_Priority_queue *priority_queue;
1291  Scheduler_Node              *scheduler_node_of_owner;
1292
1293#if defined(RTEMS_SMP)
1294  /*
1295   * Remove the priority node of each priority queue from the previous owner.
1296   * If a priority changes due to this, then register it for a priority update.
1297   */
1298
1299  fifo_node = _Thread_queue_Priority_queue_rotation( heads );
1300  fifo_head = _Chain_Immutable_head( &heads->Heads.Fifo );
1301
1302  _Priority_Actions_initialize_empty( &queue_context->Priority.Actions );
1303
1304  _Thread_Wait_acquire_default_critical( previous_owner, &lock_context );
1305
1306  do {
1307    priority_queue = (Thread_queue_Priority_queue *) fifo_node;
1308    scheduler_node_of_owner = priority_queue->scheduler_node;
1309
1310    _Assert( scheduler_node_of_owner->owner == previous_owner );
1311
1312    _Priority_Extract(
1313      &scheduler_node_of_owner->Wait.Priority,
1314      &priority_queue->Queue.Node,
1315      &queue_context->Priority.Actions,
1316      _Thread_queue_Priority_inherit_do_surrender_remove,
1317      _Thread_queue_Priority_inherit_do_surrender_change,
1318      previous_owner
1319    );
1320
1321    fifo_node = _Chain_Previous( fifo_node );
1322  } while ( fifo_node != fifo_head );
1323
1324  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
1325    /*
1326     * The previous owner performs this surrender operation.  So, it is
1327     * definitely not enqueued on a thread queue.  It is sufficient to notify
1328     * the scheduler about a priority update.  There is no need for a
1329     * _Thread_Priority_perform_actions().
1330     */
1331    _Thread_queue_Context_add_priority_update( queue_context, previous_owner );
1332  }
1333
1334  _Thread_Wait_release_default_critical( previous_owner, &lock_context );
1335
1336  /*
1337   * Remove the wait node of the new owner from the corresponding priority
1338   * queue.
1339   */
1340
1341  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
1342  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
1343
1344  do {
1345    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
1346    priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
1347
1348    _Priority_Extract(
1349      &priority_queue->Queue,
1350      &scheduler_node->Wait.Priority.Node,
1351      NULL,
1352      _Thread_queue_Priority_queue_extract,
1353      _Priority_Change_nothing,
1354      NULL
1355    );
1356
1357    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
1358  } while ( wait_node != wait_tail );
1359
1360  /* Add the priority node of the remaining priority queues to the new owner */
1361
1362  fifo_node = _Chain_First( &heads->Heads.Fifo );
1363  fifo_tail = _Chain_Immutable_tail( &heads->Heads.Fifo );
1364
1365  while ( fifo_node != fifo_tail ) {
1366    const Scheduler_Control *scheduler;
1367
1368    priority_queue = (Thread_queue_Priority_queue *) fifo_node;
1369    scheduler = _Priority_Get_scheduler( &priority_queue->Queue );
1370    scheduler_node = _Thread_Scheduler_get_node_by_index(
1371      the_thread,
1372      _Scheduler_Get_index( scheduler )
1373    );
1374
1375    priority_queue->scheduler_node = scheduler_node;
1376    _Priority_Insert(
1377      &scheduler_node->Wait.Priority,
1378      &priority_queue->Queue.Node,
1379      &queue_context->Priority.Actions,
1380      _Thread_queue_Priority_inherit_do_surrender_add,
1381      _Thread_queue_Priority_inherit_do_surrender_change_2,
1382      the_thread
1383    );
1384
1385    fifo_node = _Chain_Next( fifo_node );
1386  }
1387#else
1388  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
1389  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
1390  scheduler_node_of_owner = priority_queue->scheduler_node;
1391
1392  _Priority_Extract_non_empty(
1393    &scheduler_node_of_owner->Wait.Priority,
1394    &priority_queue->Queue.Node,
1395    &queue_context->Priority.Actions,
1396    _Thread_queue_Priority_inherit_do_surrender_change,
1397    previous_owner
1398  );
1399  _Priority_Extract(
1400    &priority_queue->Queue,
1401    &scheduler_node->Wait.Priority.Node,
1402    NULL,
1403    _Priority_Remove_nothing,
1404    _Priority_Change_nothing,
1405    NULL
1406  );
1407
1408  if ( !_Priority_Is_empty( &priority_queue->Queue ) ) {
1409    priority_queue->scheduler_node = scheduler_node;
1410    _Priority_Non_empty_insert(
1411      &scheduler_node->Wait.Priority,
1412      &priority_queue->Queue.Node,
1413      &queue_context->Priority.Actions,
1414      _Thread_queue_Priority_inherit_do_surrender_change,
1415      the_thread
1416    );
1417  }
1418#endif
1419}
1420
1421static Thread_Control *_Thread_queue_Priority_inherit_surrender(
1422  Thread_queue_Queue   *queue,
1423  Thread_queue_Heads   *heads,
1424  Thread_Control       *previous_owner,
1425  Thread_queue_Context *queue_context
1426)
1427{
1428  Thread_Control *first;
1429
1430  first = _Thread_queue_Priority_first( heads );
1431  _Thread_queue_Queue_extract(
1432    queue,
1433    heads,
1434    previous_owner,
1435    queue_context,
1436    first,
1437    _Thread_queue_Priority_inherit_do_surrender
1438  );
1439
1440  return first;
1441}
1442
1443const Thread_queue_Operations _Thread_queue_Operations_default = {
1444  .priority_actions = _Thread_queue_Do_nothing_priority_actions,
1445  .extract = _Thread_queue_Do_nothing_extract
1446  /*
1447   * The default operations are only used in _Thread_Change_priority() and
1448   * _Thread_Timeout() and don't have a thread queue associated with them, so
1449   * the enqueue and first operations are superfluous.
1450   */
1451};
1452
1453const Thread_queue_Operations _Thread_queue_Operations_FIFO = {
1454  .priority_actions = _Thread_queue_Do_nothing_priority_actions,
1455  .enqueue = _Thread_queue_FIFO_enqueue,
1456  .extract = _Thread_queue_FIFO_extract,
1457  .surrender = _Thread_queue_FIFO_surrender,
1458  .first = _Thread_queue_FIFO_first
1459};
1460
1461const Thread_queue_Operations _Thread_queue_Operations_priority = {
1462  .priority_actions = _Thread_queue_Priority_priority_actions,
1463  .enqueue = _Thread_queue_Priority_enqueue,
1464  .extract = _Thread_queue_Priority_extract,
1465  .surrender = _Thread_queue_Priority_surrender,
1466  .first = _Thread_queue_Priority_first
1467};
1468
1469const Thread_queue_Operations _Thread_queue_Operations_priority_inherit = {
1470  .priority_actions = _Thread_queue_Priority_inherit_priority_actions,
1471  .enqueue = _Thread_queue_Priority_inherit_enqueue,
1472  .extract = _Thread_queue_Priority_inherit_extract,
1473  .surrender = _Thread_queue_Priority_inherit_surrender,
1474  .first = _Thread_queue_Priority_first
1475};
Note: See TracBrowser for help on using the repository browser.