Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:27

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSScoreThreadQueue
0007  *
0008  * @brief This source file contains the definition of
0009  *   ::_Thread_queue_Operations_default, ::_Thread_queue_Operations_FIFO,
0010  *   ::_Thread_queue_Operations_priority, and
0011  *   ::_Thread_queue_Operations_priority_inherit.
0012  */
0013 
0014 /*
0015  * Copyright (C) 2015, 2021 embedded brains GmbH & Co. KG
0016  *
0017  * Redistribution and use in source and binary forms, with or without
0018  * modification, are permitted provided that the following conditions
0019  * are met:
0020  * 1. Redistributions of source code must retain the above copyright
0021  *    notice, this list of conditions and the following disclaimer.
0022  * 2. Redistributions in binary form must reproduce the above copyright
0023  *    notice, this list of conditions and the following disclaimer in the
0024  *    documentation and/or other materials provided with the distribution.
0025  *
0026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0027  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0028  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0029  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0030  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0031  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0032  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0033  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0034  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0035  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0036  * POSSIBILITY OF SUCH DAMAGE.
0037  */
0038 
0039 #ifdef HAVE_CONFIG_H
0040 #include "config.h"
0041 #endif
0042 
0043 #include <rtems/score/threadqops.h>
0044 #include <rtems/score/threadimpl.h>
0045 #include <rtems/score/assert.h>
0046 #include <rtems/score/chainimpl.h>
0047 #include <rtems/score/rbtreeimpl.h>
0048 #include <rtems/score/schedulerimpl.h>
0049 
0050 #define THREAD_QUEUE_CONTEXT_OF_PRIORITY_ACTIONS( priority_actions ) \
0051   RTEMS_CONTAINER_OF( \
0052     priority_actions, \
0053     Thread_queue_Context, \
0054     Priority.Actions \
0055   )
0056 
0057 #define THREAD_QUEUE_PRIORITY_QUEUE_OF_PRIORITY_AGGREGATION( \
0058   priority_aggregation \
0059 ) \
0060   RTEMS_CONTAINER_OF( \
0061     priority_aggregation, \
0062     Thread_queue_Priority_queue, \
0063     Queue \
0064   )
0065 
0066 void _Thread_queue_Do_nothing_priority_actions(
0067   Thread_queue_Queue *queue,
0068   Priority_Actions   *priority_actions
0069 )
0070 {
0071 #if defined(RTEMS_DEBUG) && defined(RTEMS_SMP)
0072   Priority_Aggregation *priority_aggregation;
0073 
0074   priority_aggregation = _Priority_Actions_move( priority_actions );
0075 
0076   while ( priority_aggregation != NULL ) {
0077     priority_aggregation = _Priority_Get_next_action( priority_aggregation );
0078   }
0079 #endif
0080 
0081   (void) queue;
0082   _Priority_Actions_initialize_empty( priority_actions );
0083 }
0084 
0085 static void _Thread_queue_Queue_enqueue(
0086   Thread_queue_Queue   *queue,
0087   Thread_Control       *the_thread,
0088   Thread_queue_Context *queue_context,
0089   void               ( *initialize )(
0090     Thread_queue_Queue *,
0091     Thread_Control *,
0092     Thread_queue_Context *,
0093     Thread_queue_Heads *
0094   ),
0095   void               ( *enqueue )(
0096     Thread_queue_Queue *,
0097     Thread_Control *,
0098     Thread_queue_Context *,
0099     Thread_queue_Heads *
0100   )
0101 )
0102 {
0103   Thread_queue_Heads *heads;
0104   Thread_queue_Heads *spare_heads;
0105 
0106   heads = queue->heads;
0107   spare_heads = the_thread->Wait.spare_heads;
0108   the_thread->Wait.spare_heads = NULL;
0109 
0110   if ( heads == NULL ) {
0111     _Assert( spare_heads != NULL );
0112     _Assert( _Chain_Is_empty( &spare_heads->Free_chain ) );
0113 
0114     heads = spare_heads;
0115     queue->heads = heads;
0116     _Chain_Prepend_unprotected( &heads->Free_chain, &spare_heads->Free_node );
0117     ( *initialize )( queue, the_thread, queue_context, heads );
0118   } else {
0119     _Chain_Prepend_unprotected( &heads->Free_chain, &spare_heads->Free_node );
0120     ( *enqueue )( queue, the_thread, queue_context, heads );
0121   }
0122 }
0123 
0124 static void _Thread_queue_Queue_extract(
0125   Thread_queue_Queue   *queue,
0126   Thread_queue_Heads   *heads,
0127   Thread_Control       *current_or_previous_owner,
0128   Thread_queue_Context *queue_context,
0129   Thread_Control       *the_thread,
0130   void               ( *extract )(
0131     Thread_queue_Queue *,
0132     Thread_queue_Heads *,
0133     Thread_Control *,
0134     Thread_queue_Context *,
0135     Thread_Control *
0136   )
0137 )
0138 {
0139   _Assert( heads != NULL );
0140 
0141   the_thread->Wait.spare_heads = RTEMS_CONTAINER_OF(
0142     _Chain_Get_first_unprotected( &heads->Free_chain ),
0143     Thread_queue_Heads,
0144     Free_node
0145   );
0146 
0147   if ( _Chain_Is_empty( &heads->Free_chain ) ) {
0148     queue->heads = NULL;
0149   }
0150 
0151   ( *extract )(
0152     queue,
0153     heads,
0154     current_or_previous_owner,
0155     queue_context,
0156     the_thread
0157   );
0158 }
0159 
0160 static void _Thread_queue_FIFO_do_initialize(
0161   Thread_queue_Queue   *queue,
0162   Thread_Control       *the_thread,
0163   Thread_queue_Context *queue_context,
0164   Thread_queue_Heads   *heads
0165 )
0166 {
0167   Scheduler_Node *scheduler_node;
0168 
0169   (void) queue;
0170   (void) queue_context;
0171   scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
0172 
0173   _Chain_Initialize_node( &scheduler_node->Wait.Priority.Node.Node.Chain );
0174   _Chain_Initialize_one(
0175     &heads->Heads.Fifo,
0176     &scheduler_node->Wait.Priority.Node.Node.Chain
0177   );
0178 }
0179 
0180 static void _Thread_queue_FIFO_do_enqueue(
0181   Thread_queue_Queue   *queue,
0182   Thread_Control       *the_thread,
0183   Thread_queue_Context *queue_context,
0184   Thread_queue_Heads   *heads
0185 )
0186 {
0187   Scheduler_Node *scheduler_node;
0188 
0189   scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
0190 
0191   _Chain_Initialize_node( &scheduler_node->Wait.Priority.Node.Node.Chain );
0192   _Chain_Append_unprotected(
0193     &heads->Heads.Fifo,
0194     &scheduler_node->Wait.Priority.Node.Node.Chain
0195   );
0196 }
0197 
0198 static void _Thread_queue_FIFO_do_extract(
0199   Thread_queue_Queue   *queue,
0200   Thread_queue_Heads   *heads,
0201   Thread_Control       *current_or_previous_owner,
0202   Thread_queue_Context *queue_context,
0203   Thread_Control       *the_thread
0204 )
0205 {
0206   Scheduler_Node *scheduler_node;
0207 
0208   (void) current_or_previous_owner;
0209   (void) queue_context;
0210 
0211   scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
0212 
0213   _Chain_Extract_unprotected( &scheduler_node->Wait.Priority.Node.Node.Chain );
0214 }
0215 
0216 void _Thread_queue_FIFO_enqueue(
0217   Thread_queue_Queue   *queue,
0218   Thread_Control       *the_thread,
0219   Thread_queue_Context *queue_context
0220 )
0221 {
0222   _Thread_queue_Queue_enqueue(
0223     queue,
0224     the_thread,
0225     queue_context,
0226     _Thread_queue_FIFO_do_initialize,
0227     _Thread_queue_FIFO_do_enqueue
0228   );
0229 }
0230 
0231 void _Thread_queue_FIFO_extract(
0232   Thread_queue_Queue   *queue,
0233   Thread_Control       *the_thread,
0234   Thread_queue_Context *queue_context
0235 )
0236 {
0237   _Thread_queue_Queue_extract(
0238     queue,
0239     queue->heads,
0240     NULL,
0241     queue_context,
0242     the_thread,
0243     _Thread_queue_FIFO_do_extract
0244   );
0245 }
0246 
0247 Thread_Control *_Thread_queue_FIFO_first( const Thread_queue_Heads *heads )
0248 {
0249   const Chain_Control  *fifo;
0250   const Chain_Node     *first;
0251   const Scheduler_Node *scheduler_node;
0252 
0253   fifo = &heads->Heads.Fifo;
0254   _Assert( !_Chain_Is_empty( fifo ) );
0255   first = _Chain_Immutable_first( fifo );
0256   scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY_NODE( first );
0257 
0258   return _Scheduler_Node_get_owner( scheduler_node );
0259 }
0260 
0261 Thread_Control *_Thread_queue_FIFO_surrender(
0262   Thread_queue_Queue   *queue,
0263   Thread_queue_Heads   *heads,
0264   Thread_Control       *previous_owner,
0265   Thread_queue_Context *queue_context
0266 )
0267 {
0268   Thread_Control *first;
0269 
0270   (void) previous_owner;
0271 
0272   first = _Thread_queue_FIFO_first( heads );
0273   _Thread_queue_Queue_extract(
0274     queue,
0275     heads,
0276     NULL,
0277     queue_context,
0278     first,
0279     _Thread_queue_FIFO_do_extract
0280   );
0281 
0282   return first;
0283 }
0284 
0285 static size_t _Thread_queue_Scheduler_index(
0286   const Scheduler_Node *scheduler_node
0287 )
0288 {
0289 #if defined(RTEMS_SMP)
0290   const Scheduler_Control *scheduler;
0291 
0292   scheduler = _Scheduler_Node_get_scheduler( scheduler_node );
0293   return _Scheduler_Get_index( scheduler );
0294 #else
0295   (void) scheduler_node;
0296   return 0;
0297 #endif
0298 }
0299 
0300 static Thread_queue_Priority_queue *_Thread_queue_Priority_queue_by_index(
0301   Thread_queue_Heads *heads,
0302   size_t              scheduler_index
0303 )
0304 {
0305 #if defined(RTEMS_SMP)
0306   _Assert( scheduler_index < _Scheduler_Count );
0307   return &heads->Priority[ scheduler_index ];
0308 #else
0309   (void) scheduler_index;
0310   return &heads->Heads.Priority;
0311 #endif
0312 }
0313 
0314 static Thread_queue_Priority_queue *_Thread_queue_Priority_queue(
0315   Thread_queue_Heads   *heads,
0316   const Scheduler_Node *scheduler_node
0317 )
0318 {
0319   return _Thread_queue_Priority_queue_by_index(
0320     heads,
0321     _Thread_queue_Scheduler_index( scheduler_node )
0322   );
0323 }
0324 
0325 static Chain_Node *_Thread_queue_Priority_queue_rotation(
0326   Thread_queue_Heads *heads
0327 )
0328 {
0329   Chain_Node *fifo_node;
0330 
0331 #if defined(RTEMS_SMP)
0332   /* Ensure FIFO order with respect to the priority queues */
0333   fifo_node = _Chain_First( &heads->Heads.Fifo );
0334   _Chain_Extract_unprotected( fifo_node );
0335   _Chain_Append_unprotected( &heads->Heads.Fifo, fifo_node );
0336 #else
0337   (void) heads;
0338   fifo_node = NULL;
0339 #endif
0340 
0341   return fifo_node;
0342 }
0343 
0344 #if defined(RTEMS_SMP)
0345 static void _Thread_queue_Priority_queue_extract(
0346   Priority_Aggregation *priority_aggregation,
0347   Priority_Actions     *priority_actions,
0348   void                 *arg
0349 )
0350 {
0351   Thread_queue_Priority_queue *priority_queue;
0352 
0353   (void) priority_actions;
0354   (void) arg;
0355 
0356   priority_queue = THREAD_QUEUE_PRIORITY_QUEUE_OF_PRIORITY_AGGREGATION(
0357     priority_aggregation
0358   );
0359 
0360   _Chain_Extract_unprotected( &priority_queue->Node );
0361 }
0362 #endif
0363 
0364 static void _Thread_queue_Priority_priority_actions(
0365   Thread_queue_Queue *queue,
0366   Priority_Actions   *priority_actions
0367 )
0368 {
0369   Thread_queue_Heads   *heads;
0370   Priority_Aggregation *priority_aggregation;
0371 
0372   heads = queue->heads;
0373   _Assert( heads != NULL );
0374 
0375   _Assert( !_Priority_Actions_is_empty( priority_actions ) );
0376   priority_aggregation = _Priority_Actions_move( priority_actions );
0377 
0378   do {
0379 #if defined(RTEMS_SMP)
0380     Priority_Aggregation        *next_aggregation;
0381 #endif
0382     Scheduler_Node              *scheduler_node;
0383     Thread_queue_Priority_queue *priority_queue;
0384     Priority_Action_type         priority_action_type;
0385 
0386 #if defined(RTEMS_SMP)
0387     next_aggregation = _Priority_Get_next_action( priority_aggregation );
0388 #endif
0389 
0390     scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
0391     priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
0392     priority_action_type = priority_aggregation->Action.type;
0393 
0394     switch ( priority_action_type ) {
0395 #if defined(RTEMS_SMP)
0396       case PRIORITY_ACTION_ADD:
0397         if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
0398           _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
0399         }
0400 
0401         _Priority_Plain_insert(
0402           &priority_queue->Queue,
0403           &scheduler_node->Wait.Priority.Node,
0404           _Priority_Get_priority( &scheduler_node->Wait.Priority )
0405         );
0406         break;
0407       case PRIORITY_ACTION_REMOVE:
0408         _Priority_Plain_extract(
0409           &priority_queue->Queue,
0410           &scheduler_node->Wait.Priority.Node
0411         );
0412 
0413         if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
0414           _Chain_Extract_unprotected( &priority_queue->Node );
0415         }
0416         break;
0417 #endif
0418       default:
0419         _Assert( priority_action_type == PRIORITY_ACTION_CHANGE );
0420         _Priority_Plain_changed(
0421           &priority_queue->Queue,
0422           &scheduler_node->Wait.Priority.Node
0423         );
0424         break;
0425     }
0426 
0427 #if defined(RTEMS_SMP)
0428     priority_aggregation = next_aggregation;
0429   } while ( priority_aggregation != NULL );
0430 #else
0431   } while ( false );
0432 #endif
0433 }
0434 
0435 static void _Thread_queue_Priority_do_initialize(
0436   Thread_queue_Queue   *queue,
0437   Thread_Control       *the_thread,
0438   Thread_queue_Context *queue_context,
0439   Thread_queue_Heads   *heads
0440 )
0441 {
0442   Scheduler_Node              *scheduler_node;
0443   Thread_queue_Priority_queue *priority_queue;
0444 #if defined(RTEMS_SMP)
0445   Chain_Node                  *wait_node;
0446   const Chain_Node            *wait_tail;
0447 #endif
0448 
0449   scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
0450   priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
0451 
0452   _Priority_Initialize_one(
0453     &priority_queue->Queue,
0454     &scheduler_node->Wait.Priority.Node
0455   );
0456 
0457 #if defined(RTEMS_SMP)
0458   _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
0459 
0460   wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
0461   wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
0462 
0463   while ( wait_node != wait_tail ) {
0464     scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
0465     priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
0466 
0467     _Priority_Initialize_one(
0468       &priority_queue->Queue,
0469       &scheduler_node->Wait.Priority.Node
0470     );
0471     _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
0472 
0473     wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
0474   }
0475 #endif
0476 }
0477 
0478 static void _Thread_queue_Priority_do_enqueue(
0479   Thread_queue_Queue   *queue,
0480   Thread_Control       *the_thread,
0481   Thread_queue_Context *queue_context,
0482   Thread_queue_Heads   *heads
0483 )
0484 {
0485 #if defined(RTEMS_SMP)
0486   Chain_Node       *wait_node;
0487   const Chain_Node *wait_tail;
0488 
0489   wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
0490   wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
0491 
0492   do {
0493     Scheduler_Node              *scheduler_node;
0494     Thread_queue_Priority_queue *priority_queue;
0495 
0496     scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
0497     priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
0498 
0499     if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
0500       _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
0501       _Priority_Initialize_one(
0502         &priority_queue->Queue,
0503         &scheduler_node->Wait.Priority.Node
0504       );
0505     } else {
0506       _Priority_Plain_insert(
0507         &priority_queue->Queue,
0508         &scheduler_node->Wait.Priority.Node,
0509         _Priority_Get_priority( &scheduler_node->Wait.Priority )
0510       );
0511     }
0512 
0513     wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
0514   } while ( wait_node != wait_tail );
0515 #else
0516   Scheduler_Node              *scheduler_node;
0517   Thread_queue_Priority_queue *priority_queue;
0518 
0519   scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
0520   priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
0521 
0522   _Priority_Plain_insert(
0523     &priority_queue->Queue,
0524     &scheduler_node->Wait.Priority.Node,
0525     _Priority_Get_priority( &scheduler_node->Wait.Priority )
0526   );
0527 #endif
0528 }
0529 
0530 static void _Thread_queue_Priority_do_extract(
0531   Thread_queue_Queue   *queue,
0532   Thread_queue_Heads   *heads,
0533   Thread_Control       *current_or_previous_owner,
0534   Thread_queue_Context *queue_context,
0535   Thread_Control       *the_thread
0536 )
0537 {
0538 #if defined(RTEMS_SMP)
0539   Chain_Node       *wait_node;
0540   const Chain_Node *wait_tail;
0541 
0542   wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
0543   wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
0544 
0545   do {
0546     Scheduler_Node              *scheduler_node;
0547     Thread_queue_Priority_queue *priority_queue;
0548 
0549     scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
0550     priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
0551 
0552     _Priority_Plain_extract(
0553       &priority_queue->Queue,
0554       &scheduler_node->Wait.Priority.Node
0555     );
0556 
0557     if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
0558       _Chain_Extract_unprotected( &priority_queue->Node );
0559     }
0560 
0561     wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
0562   } while ( wait_node != wait_tail );
0563 #else
0564   Scheduler_Node              *scheduler_node;
0565   Thread_queue_Priority_queue *priority_queue;
0566 
0567   scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
0568   priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
0569 
0570   _Priority_Plain_extract(
0571     &priority_queue->Queue,
0572     &scheduler_node->Wait.Priority.Node
0573   );
0574 #endif
0575 
0576   (void) current_or_previous_owner;
0577   (void) queue_context;
0578 }
0579 
0580 static void _Thread_queue_Priority_do_surrender(
0581   Thread_queue_Queue   *queue,
0582   Thread_queue_Heads   *heads,
0583   Thread_Control       *current_or_previous_owner,
0584   Thread_queue_Context *queue_context,
0585   Thread_Control       *the_thread
0586 )
0587 {
0588   _Thread_queue_Priority_queue_rotation( heads );
0589   _Thread_queue_Priority_do_extract(
0590     queue,
0591     heads,
0592     current_or_previous_owner,
0593     queue_context,
0594     the_thread
0595   );
0596 }
0597 
0598 static void _Thread_queue_Priority_enqueue(
0599   Thread_queue_Queue   *queue,
0600   Thread_Control       *the_thread,
0601   Thread_queue_Context *queue_context
0602 )
0603 {
0604   _Thread_queue_Queue_enqueue(
0605     queue,
0606     the_thread,
0607     queue_context,
0608     _Thread_queue_Priority_do_initialize,
0609     _Thread_queue_Priority_do_enqueue
0610   );
0611 }
0612 
0613 static void _Thread_queue_Priority_extract(
0614   Thread_queue_Queue   *queue,
0615   Thread_Control       *the_thread,
0616   Thread_queue_Context *queue_context
0617 )
0618 {
0619   _Thread_queue_Queue_extract(
0620     queue,
0621     queue->heads,
0622     NULL,
0623     queue_context,
0624     the_thread,
0625     _Thread_queue_Priority_do_extract
0626   );
0627 }
0628 
0629 static Thread_Control *_Thread_queue_Priority_first(
0630   const Thread_queue_Heads *heads
0631 )
0632 {
0633   const Thread_queue_Priority_queue *priority_queue;
0634   Priority_Node                     *first;
0635   Scheduler_Node                    *scheduler_node;
0636 
0637 #if defined(RTEMS_SMP)
0638   _Assert( !_Chain_Is_empty( &heads->Heads.Fifo ) );
0639   priority_queue = (Thread_queue_Priority_queue *)
0640     _Chain_First( &heads->Heads.Fifo );
0641 #else
0642   priority_queue = &heads->Heads.Priority;
0643 #endif
0644 
0645   _Assert( !_Priority_Is_empty( &priority_queue->Queue ) );
0646   first = _Priority_Get_minimum_node( &priority_queue->Queue );
0647   scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY_NODE( first );
0648 
0649   return _Scheduler_Node_get_owner( scheduler_node );
0650 }
0651 
0652 static Thread_Control *_Thread_queue_Priority_surrender(
0653   Thread_queue_Queue   *queue,
0654   Thread_queue_Heads   *heads,
0655   Thread_Control       *previous_owner,
0656   Thread_queue_Context *queue_context
0657 )
0658 {
0659   Thread_Control *first;
0660 
0661   first = _Thread_queue_Priority_first( heads );
0662   _Thread_queue_Queue_extract(
0663     queue,
0664     heads,
0665     NULL,
0666     queue_context,
0667     first,
0668     _Thread_queue_Priority_do_surrender
0669   );
0670 
0671   return first;
0672 }
0673 
0674 static void _Thread_queue_Priority_inherit_do_priority_actions_action(
0675   Priority_Aggregation *priority_aggregation,
0676   Priority_Actions     *priority_actions,
0677   Scheduler_Node       *scheduler_node_of_owner,
0678   Priority_Action_type  priority_action_type
0679 )
0680 {
0681   _Priority_Set_action(
0682     &scheduler_node_of_owner->Wait.Priority,
0683     &priority_aggregation->Node,
0684     priority_action_type
0685   );
0686   _Priority_Actions_add(
0687     priority_actions,
0688     &scheduler_node_of_owner->Wait.Priority
0689   );
0690 }
0691 
0692 #if defined(RTEMS_SMP)
0693 static void _Thread_queue_Priority_inherit_do_priority_actions_add(
0694   Priority_Aggregation *priority_aggregation,
0695   Priority_Actions     *priority_actions,
0696   void                 *arg
0697 )
0698 {
0699   _Thread_queue_Priority_inherit_do_priority_actions_action(
0700     priority_aggregation,
0701     priority_actions,
0702     arg,
0703     PRIORITY_ACTION_ADD
0704   );
0705 }
0706 
0707 static void _Thread_queue_Priority_inherit_do_priority_actions_remove(
0708   Priority_Aggregation *priority_aggregation,
0709   Priority_Actions     *priority_actions,
0710   void                 *arg
0711 )
0712 {
0713   _Thread_queue_Priority_queue_extract(
0714     priority_aggregation,
0715     priority_actions,
0716     arg
0717   );
0718   _Thread_queue_Priority_inherit_do_priority_actions_action(
0719     priority_aggregation,
0720     priority_actions,
0721     arg,
0722     PRIORITY_ACTION_REMOVE
0723   );
0724 }
0725 #endif
0726 
0727 static void _Thread_queue_Priority_inherit_do_priority_actions_change(
0728   Priority_Aggregation *priority_aggregation,
0729   Priority_Group_order  priority_group_order,
0730   Priority_Actions     *priority_actions,
0731   void                 *arg
0732 )
0733 {
0734   _Thread_queue_Priority_inherit_do_priority_actions_action(
0735     priority_aggregation,
0736     priority_actions,
0737     arg,
0738     PRIORITY_ACTION_CHANGE
0739   );
0740 }
0741 
0742 static void _Thread_queue_Priority_inherit_priority_actions(
0743   Thread_queue_Queue *queue,
0744   Priority_Actions   *priority_actions
0745 )
0746 {
0747   Thread_queue_Heads   *heads;
0748   Thread_Control       *owner;
0749   Priority_Aggregation *priority_aggregation;
0750 
0751   heads = queue->heads;
0752   _Assert( heads != NULL );
0753 
0754   owner = queue->owner;
0755   _Assert( owner != NULL );
0756 
0757   _Assert( !_Priority_Actions_is_empty( priority_actions ) );
0758   priority_aggregation = _Priority_Actions_move( priority_actions );
0759 
0760   do {
0761 #if defined(RTEMS_SMP)
0762     Priority_Aggregation        *next_aggregation;
0763 #endif
0764     Scheduler_Node              *scheduler_node;
0765     size_t                       scheduler_index;
0766     Thread_queue_Priority_queue *priority_queue;
0767     Scheduler_Node              *scheduler_node_of_owner;
0768     Priority_Action_type         priority_action_type;
0769 
0770 #if defined(RTEMS_SMP)
0771     next_aggregation = _Priority_Get_next_action( priority_aggregation );
0772 #endif
0773 
0774     scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
0775     scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
0776     priority_queue = _Thread_queue_Priority_queue_by_index(
0777       heads,
0778       scheduler_index
0779     );
0780     scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
0781       owner,
0782       scheduler_index
0783     );
0784     priority_action_type = priority_aggregation->Action.type;
0785 
0786     switch ( priority_action_type ) {
0787 #if defined(RTEMS_SMP)
0788       case PRIORITY_ACTION_ADD:
0789         if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
0790           _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
0791           priority_queue->scheduler_node = scheduler_node_of_owner;
0792         }
0793 
0794         _Priority_Insert(
0795           &priority_queue->Queue,
0796           &scheduler_node->Wait.Priority.Node,
0797           priority_actions,
0798           _Thread_queue_Priority_inherit_do_priority_actions_add,
0799           _Thread_queue_Priority_inherit_do_priority_actions_change,
0800           scheduler_node_of_owner
0801         );
0802         break;
0803       case PRIORITY_ACTION_REMOVE:
0804         _Priority_Extract(
0805           &priority_queue->Queue,
0806           &scheduler_node->Wait.Priority.Node,
0807           priority_actions,
0808           _Thread_queue_Priority_inherit_do_priority_actions_remove,
0809           _Thread_queue_Priority_inherit_do_priority_actions_change,
0810           scheduler_node_of_owner
0811         );
0812 
0813         break;
0814 #endif
0815       default:
0816         _Assert( priority_action_type == PRIORITY_ACTION_CHANGE );
0817         _Priority_Changed(
0818           &priority_queue->Queue,
0819           &scheduler_node->Wait.Priority.Node,
0820           PRIORITY_GROUP_LAST,
0821           priority_actions,
0822           _Thread_queue_Priority_inherit_do_priority_actions_change,
0823           scheduler_node_of_owner
0824         );
0825         break;
0826     }
0827 
0828 #if defined(RTEMS_SMP)
0829     priority_aggregation = next_aggregation;
0830   } while ( priority_aggregation != NULL );
0831 #else
0832   } while ( false );
0833 #endif
0834 }
0835 
0836 static void _Thread_queue_Priority_inherit_do_initialize(
0837   Thread_queue_Queue   *queue,
0838   Thread_Control       *the_thread,
0839   Thread_queue_Context *queue_context,
0840   Thread_queue_Heads   *heads
0841 )
0842 {
0843   Scheduler_Node              *scheduler_node;
0844   size_t                       scheduler_index;
0845   Thread_queue_Priority_queue *priority_queue;
0846   Thread_Control              *owner;
0847   Scheduler_Node              *scheduler_node_of_owner;
0848 #if defined(RTEMS_SMP)
0849   Chain_Node                  *wait_node;
0850   const Chain_Node            *wait_tail;
0851 #endif
0852 
0853   owner = queue->owner;
0854 
0855   scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
0856   scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
0857   priority_queue = _Thread_queue_Priority_queue_by_index(
0858     heads,
0859     scheduler_index
0860   );
0861   scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
0862     owner,
0863     scheduler_index
0864   );
0865 
0866   priority_queue->scheduler_node = scheduler_node_of_owner;
0867   _Priority_Initialize_one(
0868     &priority_queue->Queue,
0869     &scheduler_node->Wait.Priority.Node
0870   );
0871   _Priority_Actions_initialize_one(
0872     &queue_context->Priority.Actions,
0873     &scheduler_node_of_owner->Wait.Priority,
0874     &priority_queue->Queue.Node,
0875     PRIORITY_ACTION_ADD
0876   );
0877 
0878 #if defined(RTEMS_SMP)
0879   _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
0880 
0881   wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
0882   wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
0883 
0884   while ( wait_node != wait_tail ) {
0885     scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
0886     scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
0887     priority_queue = _Thread_queue_Priority_queue_by_index(
0888       heads,
0889       scheduler_index
0890     );
0891     scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
0892       owner,
0893       scheduler_index
0894     );
0895 
0896     _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
0897     priority_queue->scheduler_node = scheduler_node_of_owner;
0898     _Priority_Initialize_one(
0899       &priority_queue->Queue,
0900       &scheduler_node->Wait.Priority.Node
0901     );
0902     _Priority_Set_action(
0903       &scheduler_node_of_owner->Wait.Priority,
0904       &priority_queue->Queue.Node,
0905       PRIORITY_ACTION_ADD
0906     );
0907     _Priority_Actions_add(
0908       &queue_context->Priority.Actions,
0909       &scheduler_node_of_owner->Wait.Priority
0910     );
0911 
0912     wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
0913   }
0914 #endif
0915 
0916   _Thread_Priority_perform_actions( owner, queue_context );
0917 }
0918 
0919 static void _Thread_queue_Priority_inherit_do_enqueue_change(
0920   Priority_Aggregation *priority_aggregation,
0921   Priority_Group_order  priority_group_order,
0922   Priority_Actions     *priority_actions,
0923   void                 *arg
0924 )
0925 {
0926 #if defined(RTEMS_SMP)
0927   Scheduler_Node *scheduler_node_of_owner;
0928 
0929   scheduler_node_of_owner = arg;
0930 
0931   _Priority_Set_action(
0932     &scheduler_node_of_owner->Wait.Priority,
0933     &priority_aggregation->Node,
0934     PRIORITY_ACTION_CHANGE
0935   );
0936   _Priority_Actions_add(
0937     priority_actions,
0938     &scheduler_node_of_owner->Wait.Priority
0939   );
0940 #else
0941   Thread_queue_Queue   *queue;
0942   Thread_Control       *owner;
0943   Scheduler_Node       *scheduler_node_of_owner;
0944   Thread_queue_Context *queue_context;
0945 
0946   queue = arg;
0947   owner = queue->owner;
0948   scheduler_node_of_owner = _Thread_Scheduler_get_home_node( owner );
0949   queue_context = THREAD_QUEUE_CONTEXT_OF_PRIORITY_ACTIONS( priority_actions );
0950 
0951   _Priority_Actions_initialize_one(
0952     &queue_context->Priority.Actions,
0953     &scheduler_node_of_owner->Wait.Priority,
0954     &priority_aggregation->Node,
0955     PRIORITY_ACTION_CHANGE
0956   );
0957   _Thread_Priority_perform_actions( owner, queue_context );
0958 #endif
0959 }
0960 
0961 static void _Thread_queue_Priority_inherit_do_enqueue(
0962   Thread_queue_Queue   *queue,
0963   Thread_Control       *the_thread,
0964   Thread_queue_Context *queue_context,
0965   Thread_queue_Heads   *heads
0966 )
0967 {
0968 #if defined(RTEMS_SMP)
0969   Thread_Control   *owner;
0970   Chain_Node       *wait_node;
0971   const Chain_Node *wait_tail;
0972 
0973   owner = queue->owner;
0974   wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
0975   wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
0976 
0977   _Priority_Actions_initialize_empty( &queue_context->Priority.Actions );
0978 
0979   do {
0980     Scheduler_Node              *scheduler_node;
0981     size_t                       scheduler_index;
0982     Thread_queue_Priority_queue *priority_queue;
0983     Scheduler_Node              *scheduler_node_of_owner;
0984 
0985     scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
0986     scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
0987     priority_queue = _Thread_queue_Priority_queue_by_index(
0988       heads,
0989       scheduler_index
0990     );
0991     scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
0992       owner,
0993       scheduler_index
0994     );
0995 
0996     if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
0997       _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
0998       priority_queue->scheduler_node = scheduler_node_of_owner;
0999       _Priority_Initialize_one(
1000         &priority_queue->Queue,
1001         &scheduler_node->Wait.Priority.Node
1002       );
1003       _Priority_Set_action(
1004         &scheduler_node_of_owner->Wait.Priority,
1005         &priority_queue->Queue.Node,
1006         PRIORITY_ACTION_ADD
1007       );
1008       _Priority_Actions_add(
1009         &queue_context->Priority.Actions,
1010         &scheduler_node_of_owner->Wait.Priority
1011       );
1012     } else {
1013       _Priority_Non_empty_insert(
1014         &priority_queue->Queue,
1015         &scheduler_node->Wait.Priority.Node,
1016         &queue_context->Priority.Actions,
1017         _Thread_queue_Priority_inherit_do_enqueue_change,
1018         scheduler_node_of_owner
1019       );
1020     }
1021 
1022     wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
1023   } while ( wait_node != wait_tail );
1024 
1025   if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
1026     _Thread_Priority_perform_actions( owner, queue_context );
1027   }
1028 #else
1029   Scheduler_Node              *scheduler_node;
1030   Thread_queue_Priority_queue *priority_queue;
1031 
1032   scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
1033   priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
1034 
1035   _Priority_Non_empty_insert(
1036     &priority_queue->Queue,
1037     &scheduler_node->Wait.Priority.Node,
1038     &queue_context->Priority.Actions,
1039     _Thread_queue_Priority_inherit_do_enqueue_change,
1040     queue
1041   );
1042 #endif
1043 }
1044 
1045 static void _Thread_queue_Priority_inherit_enqueue(
1046   Thread_queue_Queue   *queue,
1047   Thread_Control       *the_thread,
1048   Thread_queue_Context *queue_context
1049 )
1050 {
1051   _Thread_queue_Queue_enqueue(
1052     queue,
1053     the_thread,
1054     queue_context,
1055     _Thread_queue_Priority_inherit_do_initialize,
1056     _Thread_queue_Priority_inherit_do_enqueue
1057   );
1058 }
1059 
1060 static void _Thread_queue_Priority_inherit_do_extract_action(
1061   Priority_Actions     *priority_actions,
1062   void                 *arg,
1063   Priority_Aggregation *priority_aggregation,
1064   Priority_Action_type  priority_action_type
1065 )
1066 {
1067 #if defined(RTEMS_SMP)
1068   Scheduler_Node *scheduler_node_of_owner;
1069 
1070   scheduler_node_of_owner = arg;
1071 
1072   _Priority_Set_action(
1073     &scheduler_node_of_owner->Wait.Priority,
1074     &priority_aggregation->Node,
1075     priority_action_type
1076   );
1077   _Priority_Actions_add(
1078     priority_actions,
1079     &scheduler_node_of_owner->Wait.Priority
1080   );
1081 #else
1082   Thread_queue_Context *queue_context;
1083   Thread_Control       *owner;
1084   Scheduler_Node       *scheduler_node_of_owner;
1085 
1086   queue_context = THREAD_QUEUE_CONTEXT_OF_PRIORITY_ACTIONS( priority_actions );
1087   owner = arg;
1088   scheduler_node_of_owner = _Thread_Scheduler_get_home_node( owner );
1089 
1090   _Priority_Actions_initialize_one(
1091     &queue_context->Priority.Actions,
1092     &scheduler_node_of_owner->Wait.Priority,
1093     &priority_aggregation->Node,
1094     priority_action_type
1095   );
1096   _Thread_Priority_perform_actions( arg, queue_context );
1097 #endif
1098 }
1099 
1100 static void _Thread_queue_Priority_inherit_do_extract_remove(
1101   Priority_Aggregation *priority_aggregation,
1102   Priority_Actions     *priority_actions,
1103   void                 *arg
1104 )
1105 {
1106   _Thread_queue_Priority_inherit_do_extract_action(
1107     priority_actions,
1108     arg,
1109     priority_aggregation,
1110     PRIORITY_ACTION_REMOVE
1111   );
1112 }
1113 
1114 static void _Thread_queue_Priority_inherit_do_extract_change(
1115   Priority_Aggregation *priority_aggregation,
1116   Priority_Group_order  priority_group_order,
1117   Priority_Actions     *priority_actions,
1118   void                 *arg
1119 )
1120 {
1121   _Thread_queue_Priority_inherit_do_extract_action(
1122     priority_actions,
1123     arg,
1124     priority_aggregation,
1125     PRIORITY_ACTION_CHANGE
1126   );
1127 }
1128 
1129 static void _Thread_queue_Priority_inherit_do_extract(
1130   Thread_queue_Queue   *queue,
1131   Thread_queue_Heads   *heads,
1132   Thread_Control       *owner,
1133   Thread_queue_Context *queue_context,
1134   Thread_Control       *the_thread
1135 )
1136 {
1137 #if defined(RTEMS_SMP)
1138   Chain_Node                  *wait_node;
1139   const Chain_Node            *wait_tail;
1140 #endif
1141   Scheduler_Node              *scheduler_node;
1142   Thread_queue_Priority_queue *priority_queue;
1143 
1144 #if defined(RTEMS_SMP)
1145   wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
1146   wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
1147 
1148   _Priority_Actions_initialize_empty( &queue_context->Priority.Actions );
1149 
1150   do {
1151     size_t          scheduler_index;
1152     Scheduler_Node *scheduler_node_of_owner;
1153 
1154     scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
1155     scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
1156     priority_queue = _Thread_queue_Priority_queue_by_index(
1157       heads,
1158       scheduler_index
1159     );
1160     scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
1161       owner,
1162       scheduler_index
1163     );
1164 
1165     _Priority_Extract(
1166       &priority_queue->Queue,
1167       &scheduler_node->Wait.Priority.Node,
1168       &queue_context->Priority.Actions,
1169       _Thread_queue_Priority_inherit_do_extract_remove,
1170       _Thread_queue_Priority_inherit_do_extract_change,
1171       scheduler_node_of_owner
1172     );
1173 
1174     if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
1175       _Chain_Extract_unprotected( &priority_queue->Node );
1176     }
1177 
1178     wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
1179   } while ( wait_node != wait_tail );
1180 
1181   if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
1182     _Thread_Priority_perform_actions( owner, queue_context );
1183   }
1184 #else
1185   scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
1186   priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
1187 
1188   _Priority_Extract(
1189     &priority_queue->Queue,
1190     &scheduler_node->Wait.Priority.Node,
1191     &queue_context->Priority.Actions,
1192     _Thread_queue_Priority_inherit_do_extract_remove,
1193     _Thread_queue_Priority_inherit_do_extract_change,
1194     owner
1195   );
1196 #endif
1197 }
1198 
1199 static void _Thread_queue_Priority_inherit_extract(
1200   Thread_queue_Queue   *queue,
1201   Thread_Control       *the_thread,
1202   Thread_queue_Context *queue_context
1203 )
1204 {
1205 #if defined(RTEMS_SMP)
1206   /*
1207    * We must lock the thread wait path for the complete extract operation
1208    * including the thread queue head management.  Consider the following
1209    * scenario on three processors.  Thread T0 owns thread queue A, thread T1
1210    * owns thread queue B and thread T2 owns thread queue C.  Thread T0 waits
1211    * for B and thread T1 waits for C.
1212    *
1213    * A <-------------------------\
1214    *  \                          |
1215    *   > T0 -> B                 |
1216    *            \                |
1217    *             > T1 -> C       |
1218    *                      \      |
1219    *                       > T2 -/
1220    *
1221    * Now three things happen at the same time
1222    *  - thread T0 times out,
1223    *  - thread T1 times out,
1224    *  - thread T2 tries to enqueue on a thread queue A.
1225    *
1226    * Thread T1 acquires thread queue lock C and waits for thread queue lock A.
1227    * Thread T2 acquires thread queue lock A and waits for thread queue lock B.
1228    * Thread T0 acquires thread queue lock B and detects a potential deadlock.
1229    * Thread T0 carries out the thread queue extraction due to the timeout and
1230    * uses the thread wait path segments acquired by thread T1 and T2.  This
1231    * resolves the deadlock.  Thread T1 and T2 can the complete their
1232    * operations.
1233    */
1234   (void) _Thread_queue_Path_acquire( queue, the_thread, queue_context );
1235 #endif
1236 
1237   _Thread_queue_Queue_extract(
1238     queue,
1239     queue->heads,
1240     queue->owner,
1241     queue_context,
1242     the_thread,
1243     _Thread_queue_Priority_inherit_do_extract
1244   );
1245 
1246 #if defined(RTEMS_SMP)
1247   _Thread_queue_Path_release( queue_context );
1248 #endif
1249 }
1250 
1251 #if defined(RTEMS_SMP)
1252 static void _Thread_queue_Priority_inherit_do_surrender_add(
1253   Priority_Aggregation *priority_aggregation,
1254   Priority_Actions     *priority_actions,
1255   void                 *arg
1256 )
1257 {
1258   Scheduler_Node *scheduler_node;
1259   Thread_Control *the_thread;
1260 
1261   scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
1262   the_thread = arg;
1263 
1264   _Thread_Scheduler_add_wait_node( the_thread, scheduler_node );
1265   _Scheduler_Node_set_priority(
1266     scheduler_node,
1267     _Priority_Get_priority( priority_aggregation ),
1268     PRIORITY_GROUP_LAST
1269   );
1270 }
1271 
1272 static void _Thread_queue_Priority_inherit_do_surrender_remove(
1273   Priority_Aggregation *priority_aggregation,
1274   Priority_Actions     *priority_actions,
1275   void                 *arg
1276 )
1277 {
1278   Scheduler_Node *scheduler_node;
1279   Thread_Control *the_thread;
1280 
1281   scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
1282   the_thread = arg;
1283 
1284   _Thread_Scheduler_remove_wait_node( the_thread, scheduler_node );
1285   _Priority_Actions_add( priority_actions, priority_aggregation );
1286 }
1287 #endif
1288 
1289 static void _Thread_queue_Priority_inherit_do_surrender_change(
1290   Priority_Aggregation *priority_aggregation,
1291   Priority_Group_order  priority_group_order,
1292   Priority_Actions     *priority_actions,
1293   void                 *arg
1294 )
1295 {
1296 #if defined(RTEMS_SMP)
1297   _Priority_Actions_add( priority_actions, priority_aggregation );
1298 #else
1299   _Thread_queue_Context_add_priority_update(
1300     THREAD_QUEUE_CONTEXT_OF_PRIORITY_ACTIONS( priority_actions ),
1301     arg
1302   );
1303 #endif
1304   _Scheduler_Node_set_priority(
1305     SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation ),
1306     _Priority_Get_priority( priority_aggregation ),
1307     priority_group_order
1308   );
1309 }
1310 
1311 #if defined(RTEMS_SMP)
1312 static void _Thread_queue_Priority_inherit_do_surrender_change_2(
1313   Priority_Aggregation *priority_aggregation,
1314   Priority_Group_order  priority_group_order,
1315   Priority_Actions     *priority_actions,
1316   void                 *arg
1317 )
1318 {
1319   _Scheduler_Node_set_priority(
1320     SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation ),
1321     _Priority_Get_priority( priority_aggregation ),
1322     priority_group_order
1323   );
1324 }
1325 #endif
1326 
1327 static void _Thread_queue_Priority_inherit_do_surrender(
1328   Thread_queue_Queue   *queue,
1329   Thread_queue_Heads   *heads,
1330   Thread_Control       *previous_owner,
1331   Thread_queue_Context *queue_context,
1332   Thread_Control       *the_thread
1333 )
1334 {
1335 #if defined(RTEMS_SMP)
1336   Chain_Node                  *fifo_node;
1337   const Chain_Node            *fifo_head;
1338   const Chain_Node            *fifo_tail;
1339   Chain_Node                  *wait_node;
1340   const Chain_Node            *wait_tail;
1341   ISR_lock_Context             lock_context;
1342 #endif
1343   Scheduler_Node              *scheduler_node;
1344   Thread_queue_Priority_queue *priority_queue;
1345   Scheduler_Node              *scheduler_node_of_owner;
1346 
1347 #if defined(RTEMS_SMP)
1348   /*
1349    * Remove the priority node of each priority queue from the previous owner.
1350    * If a priority changes due to this, then register it for a priority update.
1351    */
1352 
1353   fifo_node = _Thread_queue_Priority_queue_rotation( heads );
1354   fifo_head = _Chain_Immutable_head( &heads->Heads.Fifo );
1355 
1356   _Priority_Actions_initialize_empty( &queue_context->Priority.Actions );
1357 
1358   _Thread_Wait_acquire_default_critical( previous_owner, &lock_context );
1359 
1360   do {
1361     priority_queue = (Thread_queue_Priority_queue *) fifo_node;
1362     scheduler_node_of_owner = priority_queue->scheduler_node;
1363 
1364     _Assert( scheduler_node_of_owner->owner == previous_owner );
1365 
1366     _Priority_Extract(
1367       &scheduler_node_of_owner->Wait.Priority,
1368       &priority_queue->Queue.Node,
1369       &queue_context->Priority.Actions,
1370       _Thread_queue_Priority_inherit_do_surrender_remove,
1371       _Thread_queue_Priority_inherit_do_surrender_change,
1372       previous_owner
1373     );
1374 
1375     fifo_node = _Chain_Previous( fifo_node );
1376   } while ( fifo_node != fifo_head );
1377 
1378   if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
1379     /*
1380      * The previous owner performs this surrender operation.  So, it is
1381      * definitely not enqueued on a thread queue.  It is sufficient to notify
1382      * the scheduler about a priority update.  There is no need for a
1383      * _Thread_Priority_perform_actions().
1384      */
1385     _Thread_queue_Context_add_priority_update( queue_context, previous_owner );
1386 #if defined(RTEMS_DEBUG)
1387     _Thread_queue_Do_nothing_priority_actions( queue, &queue_context->Priority.Actions );
1388 #endif
1389   }
1390 
1391   _Thread_Wait_release_default_critical( previous_owner, &lock_context );
1392 
1393   /*
1394    * Remove the wait node of the new owner from the corresponding priority
1395    * queue.
1396    */
1397 
1398   wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
1399   wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
1400 
1401   do {
1402     scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
1403     priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
1404 
1405     _Priority_Extract(
1406       &priority_queue->Queue,
1407       &scheduler_node->Wait.Priority.Node,
1408       NULL,
1409       _Thread_queue_Priority_queue_extract,
1410       _Priority_Change_nothing,
1411       NULL
1412     );
1413 
1414     wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
1415   } while ( wait_node != wait_tail );
1416 
1417   /* Add the priority node of the remaining priority queues to the new owner */
1418 
1419   fifo_node = _Chain_First( &heads->Heads.Fifo );
1420   fifo_tail = _Chain_Immutable_tail( &heads->Heads.Fifo );
1421 
1422   while ( fifo_node != fifo_tail ) {
1423     const Scheduler_Control *scheduler;
1424 
1425     priority_queue = (Thread_queue_Priority_queue *) fifo_node;
1426     scheduler = _Priority_Get_scheduler( &priority_queue->Queue );
1427     scheduler_node = _Thread_Scheduler_get_node_by_index(
1428       the_thread,
1429       _Scheduler_Get_index( scheduler )
1430     );
1431 
1432     priority_queue->scheduler_node = scheduler_node;
1433     _Priority_Insert(
1434       &scheduler_node->Wait.Priority,
1435       &priority_queue->Queue.Node,
1436       &queue_context->Priority.Actions,
1437       _Thread_queue_Priority_inherit_do_surrender_add,
1438       _Thread_queue_Priority_inherit_do_surrender_change_2,
1439       the_thread
1440     );
1441 
1442     fifo_node = _Chain_Next( fifo_node );
1443   }
1444 #else
1445   scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
1446   priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
1447   scheduler_node_of_owner = priority_queue->scheduler_node;
1448 
1449   _Priority_Extract_non_empty(
1450     &scheduler_node_of_owner->Wait.Priority,
1451     &priority_queue->Queue.Node,
1452     &queue_context->Priority.Actions,
1453     _Thread_queue_Priority_inherit_do_surrender_change,
1454     previous_owner
1455   );
1456   _Priority_Extract(
1457     &priority_queue->Queue,
1458     &scheduler_node->Wait.Priority.Node,
1459     NULL,
1460     _Priority_Remove_nothing,
1461     _Priority_Change_nothing,
1462     NULL
1463   );
1464 
1465   if ( !_Priority_Is_empty( &priority_queue->Queue ) ) {
1466     priority_queue->scheduler_node = scheduler_node;
1467     _Priority_Non_empty_insert(
1468       &scheduler_node->Wait.Priority,
1469       &priority_queue->Queue.Node,
1470       &queue_context->Priority.Actions,
1471       _Thread_queue_Priority_inherit_do_surrender_change,
1472       the_thread
1473     );
1474   }
1475 #endif
1476 }
1477 
1478 static Thread_Control *_Thread_queue_Priority_inherit_surrender(
1479   Thread_queue_Queue   *queue,
1480   Thread_queue_Heads   *heads,
1481   Thread_Control       *previous_owner,
1482   Thread_queue_Context *queue_context
1483 )
1484 {
1485   Thread_Control *first;
1486 
1487   first = _Thread_queue_Priority_first( heads );
1488   _Thread_queue_Queue_extract(
1489     queue,
1490     heads,
1491     previous_owner,
1492     queue_context,
1493     first,
1494     _Thread_queue_Priority_inherit_do_surrender
1495   );
1496 
1497   return first;
1498 }
1499 
1500 const Thread_queue_Operations _Thread_queue_Operations_default = {
1501   .priority_actions = _Thread_queue_Do_nothing_priority_actions
1502   /*
1503    * The default operations are only used in _Thread_Priority_apply() and
1504    * _Thread_Continue() and do not have a thread queue associated with them, so
1505    * the enqueue, extract, surrender, and first operations are superfluous.
1506    */
1507 };
1508 
1509 const Thread_queue_Operations _Thread_queue_Operations_FIFO = {
1510   .priority_actions = _Thread_queue_Do_nothing_priority_actions,
1511   .enqueue = _Thread_queue_FIFO_enqueue,
1512   .extract = _Thread_queue_FIFO_extract,
1513   .surrender = _Thread_queue_FIFO_surrender,
1514   .first = _Thread_queue_FIFO_first
1515 };
1516 
1517 const Thread_queue_Operations _Thread_queue_Operations_priority = {
1518   .priority_actions = _Thread_queue_Priority_priority_actions,
1519   .enqueue = _Thread_queue_Priority_enqueue,
1520   .extract = _Thread_queue_Priority_extract,
1521   .surrender = _Thread_queue_Priority_surrender,
1522   .first = _Thread_queue_Priority_first
1523 };
1524 
1525 const Thread_queue_Operations _Thread_queue_Operations_priority_inherit = {
1526   .priority_actions = _Thread_queue_Priority_inherit_priority_actions,
1527   .enqueue = _Thread_queue_Priority_inherit_enqueue,
1528   .extract = _Thread_queue_Priority_inherit_extract,
1529   .surrender = _Thread_queue_Priority_inherit_surrender,
1530   .first = _Thread_queue_Priority_first
1531 };