source: rtems/cpukit/score/src/threadqops.c @ 255fe43

Last change on this file since 255fe43 was 255fe43, checked in by Joel Sherrill <joel@…>, on 03/01/22 at 20:40:44

cpukit/: Scripted embedded brains header file clean up

Updates #4625.

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