[rtems commit] score: Scheduler node awareness for thread queues

Sebastian Huber sebh at rtems.org
Wed Sep 21 07:06:42 UTC 2016


Module:    rtems
Branch:    master
Commit:    f6142c19f192e40ee1aa9ff67eb1c711343c157d
Changeset: http://git.rtems.org/rtems/commit/?id=f6142c19f192e40ee1aa9ff67eb1c711343c157d

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Fri Sep  9 11:00:06 2016 +0200

score: Scheduler node awareness for thread queues

Maintain the priority of a thread for each scheduler instance via the
thread queue enqueue, extract, priority actions and surrender
operations.  This replaces the primitive priority boosting.

Update #2556.

---

 cpukit/score/include/rtems/score/schedulernode.h |   5 +
 cpukit/score/include/rtems/score/threadimpl.h    |  45 +-
 cpukit/score/include/rtems/score/threadq.h       |  11 +-
 cpukit/score/include/rtems/score/threadqimpl.h   |   6 +-
 cpukit/score/src/threadchangepriority.c          |  50 +-
 cpukit/score/src/threadqenqueue.c                |  97 ++-
 cpukit/score/src/threadqops.c                    | 979 +++++++++++++++++------
 testsuites/smptests/smpmutex01/init.c            | 373 ++++++++-
 8 files changed, 1217 insertions(+), 349 deletions(-)

diff --git a/cpukit/score/include/rtems/score/schedulernode.h b/cpukit/score/include/rtems/score/schedulernode.h
index 8d00a43..2397ba4 100644
--- a/cpukit/score/include/rtems/score/schedulernode.h
+++ b/cpukit/score/include/rtems/score/schedulernode.h
@@ -209,6 +209,11 @@ typedef struct Scheduler_Node {
 extern const size_t _Scheduler_Node_size;
 #endif
 
+#if defined(RTEMS_SMP)
+#define SCHEDULER_NODE_OF_THREAD_WAIT_NODE( node ) \
+  RTEMS_CONTAINER_OF( node, Scheduler_Node, Thread.Wait_node )
+#endif
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h
index 09af9c1..7b978ea 100644
--- a/cpukit/score/include/rtems/score/threadimpl.h
+++ b/cpukit/score/include/rtems/score/threadimpl.h
@@ -997,6 +997,20 @@ RTEMS_INLINE_ROUTINE Scheduler_Node *_Thread_Scheduler_get_own_node(
 #endif
 }
 
+RTEMS_INLINE_ROUTINE Scheduler_Node *_Thread_Scheduler_get_home_node(
+  const Thread_Control *the_thread
+)
+{
+#if defined(RTEMS_SMP)
+  _Assert( !_Chain_Is_empty( &the_thread->Scheduler.Wait_nodes ) );
+  return SCHEDULER_NODE_OF_THREAD_WAIT_NODE(
+    _Chain_First( &the_thread->Scheduler.Wait_nodes )
+  );
+#else
+  return the_thread->Scheduler.nodes;
+#endif
+}
+
 RTEMS_INLINE_ROUTINE Scheduler_Node *_Thread_Scheduler_get_node_by_index(
   const Thread_Control *the_thread,
   size_t                scheduler_index
@@ -1308,21 +1322,22 @@ RTEMS_INLINE_ROUTINE void _Thread_Wait_release(
 }
 
 /**
- * @brief Claims the thread wait queue and operations.
+ * @brief Claims the thread wait queue.
  *
  * The caller must not be the owner of the default thread wait lock.  The
- * caller must be the owner of the corresponding thread queue lock.
+ * caller must be the owner of the corresponding thread queue lock.  The
+ * registration of the corresponding thread queue operations is deferred and
+ * done after the deadlock detection.  This is crucial to support timeouts on
+ * SMP configurations.
  *
  * @param[in] the_thread The thread.
  * @param[in] queue The new thread queue.
- * @param[in] operations The new thread operations.
  *
- * @see _Thread_Wait_restore_default().
+ * @see _Thread_Wait_claim_finalize() and _Thread_Wait_restore_default().
  */
 RTEMS_INLINE_ROUTINE void _Thread_Wait_claim(
-  Thread_Control                *the_thread,
-  Thread_queue_Queue            *queue,
-  const Thread_queue_Operations *operations
+  Thread_Control     *the_thread,
+  Thread_queue_Queue *queue
 )
 {
   ISR_lock_Context lock_context;
@@ -1338,12 +1353,26 @@ RTEMS_INLINE_ROUTINE void _Thread_Wait_claim(
 #endif
 
   the_thread->Wait.queue = queue;
-  the_thread->Wait.operations = operations;
 
   _Thread_Wait_release_default_critical( the_thread, &lock_context );
 }
 
 /**
+ * @brief Finalizes the thread wait queue claim via registration of the
+ * corresponding thread queue operations.
+ *
+ * @param[in] the_thread The thread.
+ * @param[in] operations The corresponding thread queue operations.
+ */
+RTEMS_INLINE_ROUTINE void _Thread_Wait_claim_finalize(
+  Thread_Control                *the_thread,
+  const Thread_queue_Operations *operations
+)
+{
+  the_thread->Wait.operations = operations;
+}
+
+/**
  * @brief Removes a thread wait lock request.
  *
  * On SMP configurations, removes a thread wait lock request.
diff --git a/cpukit/score/include/rtems/score/threadq.h b/cpukit/score/include/rtems/score/threadq.h
index 6f62506..084161c 100644
--- a/cpukit/score/include/rtems/score/threadq.h
+++ b/cpukit/score/include/rtems/score/threadq.h
@@ -216,6 +216,12 @@ typedef struct {
      * @brief The start of a thread queue path.
      */
     Thread_queue_Link Start;
+
+    /**
+     * @brief In case of a deadlock, a link for the first thread on the path
+     * that tries to enqueue on a thread queue.
+     */
+    Thread_queue_Link Deadlock;
   } Path;
 #endif
 
@@ -345,11 +351,6 @@ typedef struct _Thread_queue_Heads {
 
 #if defined(RTEMS_SMP)
   /**
-   * @brief Boost priority.
-   */
-  Priority_Node Boost_priority;
-
-  /**
    * @brief One priority queue per scheduler instance.
    */
   Thread_queue_Priority_queue Priority[ RTEMS_ZERO_LENGTH_ARRAY ];
diff --git a/cpukit/score/include/rtems/score/threadqimpl.h b/cpukit/score/include/rtems/score/threadqimpl.h
index 65b0e8e..e24beec 100644
--- a/cpukit/score/include/rtems/score/threadqimpl.h
+++ b/cpukit/score/include/rtems/score/threadqimpl.h
@@ -280,12 +280,10 @@ RTEMS_INLINE_ROUTINE void _Thread_queue_Heads_initialize(
 #if defined(RTEMS_SMP)
   size_t i;
 
-  _Priority_Node_initialize( &heads->Boost_priority, 0 );
-  _Priority_Node_set_inactive( &heads->Boost_priority );
-
   for ( i = 0; i < _Scheduler_Count; ++i ) {
     _Chain_Initialize_node( &heads->Priority[ i ].Node );
     _Priority_Initialize_empty( &heads->Priority[ i ].Queue );
+    heads->Priority[ i ].Queue.scheduler = &_Scheduler_Table[ i ];
   }
 #endif
 
@@ -955,6 +953,7 @@ void _Thread_queue_Unblock_proxy(
 );
 #endif
 
+#if defined(RTEMS_SMP)
 bool _Thread_queue_Path_acquire_critical(
   Thread_queue_Queue   *queue,
   Thread_Control       *the_thread,
@@ -964,6 +963,7 @@ bool _Thread_queue_Path_acquire_critical(
 void _Thread_queue_Path_release_critical(
   Thread_queue_Context *queue_context
 );
+#endif
 
 /**
  * @brief Helper structure to ensure that all objects containing a thread queue
diff --git a/cpukit/score/src/threadchangepriority.c b/cpukit/score/src/threadchangepriority.c
index c10c712..41b6382 100644
--- a/cpukit/score/src/threadchangepriority.c
+++ b/cpukit/score/src/threadchangepriority.c
@@ -44,6 +44,16 @@ static void _Thread_Priority_action_add(
   void                 *arg
 )
 {
+  Scheduler_Node *scheduler_node;
+  Thread_Control *the_thread;
+
+  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
+  the_thread = arg;
+
+  _Chain_Append_unprotected(
+    &the_thread->Scheduler.Wait_nodes,
+    &scheduler_node->Thread.Wait_node
+  );
   _Thread_Set_scheduler_node_priority( priority_aggregation, false );
   _Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_ADD );
   _Priority_Actions_add( priority_actions, priority_aggregation );
@@ -55,6 +65,11 @@ static void _Thread_Priority_action_remove(
   void                 *arg
 )
 {
+  Scheduler_Node *scheduler_node;
+
+  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
+
+  _Chain_Extract_unprotected( &scheduler_node->Thread.Wait_node );
   _Thread_Set_scheduler_node_priority( priority_aggregation, true );
   _Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_REMOVE );
   _Priority_Actions_add( priority_actions, priority_aggregation );
@@ -107,7 +122,7 @@ static void _Thread_Priority_do_perform_actions(
           &queue_context->Priority.Actions,
           _Thread_Priority_action_add,
           _Thread_Priority_action_change,
-          NULL
+          the_thread
         );
 #else
         _Priority_Non_empty_insert(
@@ -157,6 +172,7 @@ static void _Thread_Priority_do_perform_actions(
 
   if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
     _Thread_queue_Context_add_priority_update( queue_context, the_thread );
+
     ( *operations->priority_actions )(
       queue,
       &queue_context->Priority.Actions
@@ -169,29 +185,27 @@ void _Thread_Priority_perform_actions(
   Thread_queue_Context *queue_context
 )
 {
-#if defined(RTEMS_SMP)
-  Thread_queue_Link *link;
-#endif
-  Thread_Control    *the_thread;
-  size_t             update_count;
+  Thread_Control *the_thread;
+  size_t          update_count;
 
   _Assert( start_of_path != NULL );
 
-#if defined(RTEMS_SMP)
-  link = &queue_context->Path.Start;
-#endif
+  /*
+   * This function is tricky on SMP configurations.  Please note that we do not
+   * use the thread queue path available via the thread queue context.  Instead
+   * we directly use the thread wait information to traverse the thread queue
+   * path.  Thus, we do not necessarily acquire all thread queue locks on our
+   * own.  In case of a deadlock, we use locks acquired by other processors
+   * along the path.
+   */
+
   the_thread = start_of_path;
   update_count = _Thread_queue_Context_save_priority_updates( queue_context );
 
   while ( true ) {
     Thread_queue_Queue *queue;
 
-#if defined(RTEMS_SMP)
-    _Assert( link->owner == the_thread );
-    queue = link->Lock_context.Wait.queue;
-#else
     queue = the_thread->Wait.queue;
-#endif
 
     _Thread_Priority_do_perform_actions(
       the_thread,
@@ -209,10 +223,6 @@ void _Thread_Priority_perform_actions(
     the_thread = queue->owner;
     _Assert( the_thread != NULL );
 
-#if defined(RTEMS_SMP)
-    link = THREAD_QUEUE_LINK_OF_PATH_NODE( _Chain_Next( &link->Path_node ) );
-#endif
-
     /*
      * In case the priority action list is non-empty, then the current thread
      * is enqueued on a thread queue.  There is no need to notify the scheduler
@@ -255,9 +265,13 @@ static void _Thread_Priority_apply(
   );
 
   if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
+#if defined(RTEMS_SMP)
     _Thread_queue_Path_acquire_critical( queue, the_thread, queue_context );
+#endif
     _Thread_Priority_perform_actions( queue->owner, queue_context );
+#if defined(RTEMS_SMP)
     _Thread_queue_Path_release_critical( queue_context );
+#endif
   }
 }
 
diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c
index 2864c09..362ce8f 100644
--- a/cpukit/score/src/threadqenqueue.c
+++ b/cpukit/score/src/threadqenqueue.c
@@ -114,6 +114,9 @@ static bool _Thread_queue_Link_add(
   Thread_queue_Queue *recursive_target;
   ISR_lock_Context    lock_context;
 
+  link->source = source;
+  link->target = target;
+
   links = &_Thread_queue_Links;
   recursive_target = target;
 
@@ -136,8 +139,6 @@ static bool _Thread_queue_Link_add(
     }
   }
 
-  link->source = source;
-  link->target = target;
   _RBTree_Insert_inline(
     &links->Links,
     &link->Registry_node,
@@ -162,6 +163,9 @@ static void _Thread_queue_Link_remove( Thread_queue_Link *link )
 }
 #endif
 
+#if !defined(RTEMS_SMP)
+static
+#endif
 void _Thread_queue_Path_release_critical(
   Thread_queue_Context *queue_context
 )
@@ -173,51 +177,80 @@ void _Thread_queue_Path_release_critical(
   head = _Chain_Head( &queue_context->Path.Links );
   node = _Chain_Last( &queue_context->Path.Links );
 
-  if ( head != node ) {
+  while ( head != node ) {
     Thread_queue_Link *link;
 
-    /*
-     * The terminal link may have an owner which does not wait on a thread
-     * queue.
-     */
-
     link = THREAD_QUEUE_LINK_OF_PATH_NODE( node );
 
-    if ( link->Lock_context.Wait.queue == NULL ) {
-      _Thread_Wait_release_default_critical(
-        link->owner,
-        &link->Lock_context.Lock_context
-      );
-
-      node = _Chain_Previous( node );
-#if defined(RTEMS_DEBUG)
-      _Chain_Set_off_chain( &link->Path_node );
-#endif
-    }
-
-    while ( head != node ) {
-      /* The other links have an owner which waits on a thread queue */
-      link = THREAD_QUEUE_LINK_OF_PATH_NODE( node );
-      _Assert( link->Lock_context.Wait.queue != NULL );
-
+    if ( link->Lock_context.Wait.queue != NULL ) {
       _Thread_queue_Link_remove( link );
       _Thread_Wait_release_queue_critical(
         link->Lock_context.Wait.queue,
         &link->Lock_context
       );
       _Thread_Wait_remove_request( link->owner, &link->Lock_context );
+    } else {
+      _Thread_Wait_release_default_critical(
+        link->owner,
+        &link->Lock_context.Lock_context
+      );
+    }
 
-      node = _Chain_Previous( node );
+    node = _Chain_Previous( node );
 #if defined(RTEMS_DEBUG)
-      _Chain_Set_off_chain( &link->Path_node );
+    _Chain_Set_off_chain( &link->Path_node );
 #endif
-    }
   }
 #else
   (void) queue_context;
 #endif
 }
 
+#if defined(RTEMS_SMP)
+static void _Thread_queue_Path_append_deadlock_thread(
+  Thread_Control       *the_thread,
+  Thread_queue_Context *queue_context
+)
+{
+  Thread_Control *deadlock;
+
+  /*
+   * In case of a deadlock, we must obtain the thread wait default lock for the
+   * first thread on the path that tries to enqueue on a thread queue.  This
+   * thread can be identified by the thread wait operations.  This lock acquire
+   * is necessary for the timeout and explicit thread priority changes, see
+   * _Thread_Priority_perform_actions().
+   */
+
+  deadlock = NULL;
+
+  while ( the_thread->Wait.operations != &_Thread_queue_Operations_default ) {
+    the_thread = the_thread->Wait.queue->owner;
+    deadlock = the_thread;
+  }
+
+  if ( deadlock != NULL ) {
+    Thread_queue_Link *link;
+
+    link = &queue_context->Path.Deadlock;
+    _Chain_Initialize_node( &link->Path_node );
+    _Chain_Append_unprotected(
+      &queue_context->Path.Links,
+      &link->Path_node
+    );
+    link->owner = deadlock;
+    link->Lock_context.Wait.queue = NULL;
+    _Thread_Wait_acquire_default_critical(
+      deadlock,
+      &link->Lock_context.Lock_context
+    );
+  }
+}
+#endif
+
+#if !defined(RTEMS_SMP)
+static
+#endif
 bool _Thread_queue_Path_acquire_critical(
   Thread_queue_Queue   *queue,
   Thread_Control       *the_thread,
@@ -249,12 +282,12 @@ bool _Thread_queue_Path_acquire_critical(
     return false;
   }
 
-  _RBTree_Initialize_node( &queue_context->Path.Start.Registry_node );
-  _Chain_Initialize_node( &queue_context->Path.Start.Path_node );
   _Chain_Initialize_node(
     &queue_context->Path.Start.Lock_context.Wait.Gate.Node
   );
   link = &queue_context->Path.Start;
+  _RBTree_Initialize_node( &link->Registry_node );
+  _Chain_Initialize_node( &link->Path_node );
 
   do {
     _Chain_Append_unprotected( &queue_context->Path.Links, &link->Path_node );
@@ -293,6 +326,7 @@ bool _Thread_queue_Path_acquire_critical(
         }
       } else {
         link->Lock_context.Wait.queue = NULL;
+        _Thread_queue_Path_append_deadlock_thread( owner, queue_context );
         return false;
       }
     } else {
@@ -353,7 +387,7 @@ void _Thread_queue_Enqueue_critical(
   }
 #endif
 
-  _Thread_Wait_claim( the_thread, queue, operations );
+  _Thread_Wait_claim( the_thread, queue );
 
   if ( !_Thread_queue_Path_acquire_critical( queue, the_thread, queue_context ) ) {
     _Thread_queue_Path_release_critical( queue_context );
@@ -365,6 +399,7 @@ void _Thread_queue_Enqueue_critical(
   }
 
   _Thread_queue_Context_clear_priority_updates( queue_context );
+  _Thread_Wait_claim_finalize( the_thread, operations );
   ( *operations->enqueue )( queue, the_thread, queue_context );
 
   _Thread_queue_Path_release_critical( queue_context );
diff --git a/cpukit/score/src/threadqops.c b/cpukit/score/src/threadqops.c
index 602d6bb..f212f25 100644
--- a/cpukit/score/src/threadqops.c
+++ b/cpukit/score/src/threadqops.c
@@ -256,8 +256,7 @@ static Thread_Control *_Thread_queue_FIFO_surrender(
   return first;
 }
 
-static Thread_queue_Priority_queue *_Thread_queue_Priority_queue(
-  Thread_queue_Heads   *heads,
+static size_t _Thread_queue_Scheduler_index(
   const Scheduler_Node *scheduler_node
 )
 {
@@ -265,13 +264,76 @@ static Thread_queue_Priority_queue *_Thread_queue_Priority_queue(
   const Scheduler_Control *scheduler;
 
   scheduler = _Priority_Get_scheduler( &scheduler_node->Wait.Priority );
-  return &heads->Priority[ _Scheduler_Get_index( scheduler ) ];
+  return _Scheduler_Get_index( scheduler );
 #else
   (void) scheduler_node;
+  return 0;
+#endif
+}
+
+static Thread_queue_Priority_queue *_Thread_queue_Priority_queue_by_index(
+  Thread_queue_Heads *heads,
+  size_t              scheduler_index
+)
+{
+#if defined(RTEMS_SMP)
+  return &heads->Priority[ scheduler_index ];
+#else
+  (void) scheduler_index;
   return &heads->Heads.Priority;
 #endif
 }
 
+static Thread_queue_Priority_queue *_Thread_queue_Priority_queue(
+  Thread_queue_Heads   *heads,
+  const Scheduler_Node *scheduler_node
+)
+{
+  return _Thread_queue_Priority_queue_by_index(
+    heads,
+    _Thread_queue_Scheduler_index( scheduler_node )
+  );
+}
+
+static Chain_Node *_Thread_queue_Priority_queue_rotation(
+  Thread_queue_Heads *heads
+)
+{
+  Chain_Node *fifo_node;
+
+#if defined(RTEMS_SMP)
+  /* Ensure FIFO order with respect to the priority queues */
+  fifo_node = _Chain_First( &heads->Heads.Fifo );
+  _Chain_Extract_unprotected( fifo_node );
+  _Chain_Append_unprotected( &heads->Heads.Fifo, fifo_node );
+#else
+  (void) heads;
+  fifo_node = NULL;
+#endif
+
+  return fifo_node;
+}
+
+#if defined(RTEMS_SMP)
+static void _Thread_queue_Priority_queue_extract(
+  Priority_Aggregation *priority_aggregation,
+  Priority_Actions     *priority_actions,
+  void                 *arg
+)
+{
+  Thread_queue_Priority_queue *priority_queue;
+
+  (void) priority_actions;
+  (void) arg;
+
+  priority_queue = THREAD_QUEUE_PRIORITY_QUEUE_OF_PRIORITY_AGGREGATION(
+    priority_aggregation
+  );
+
+  _Chain_Extract_unprotected( &priority_queue->Node );
+}
+#endif
+
 static void _Thread_queue_Priority_priority_actions(
   Thread_queue_Queue *queue,
   Priority_Actions   *priority_actions
@@ -289,15 +351,36 @@ static void _Thread_queue_Priority_priority_actions(
   do {
     Scheduler_Node              *scheduler_node;
     Thread_queue_Priority_queue *priority_queue;
+    Priority_Action_type         priority_action_type;
 
     scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
     priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+    priority_action_type = priority_aggregation->Action.type;
 
-    _Assert( priority_aggregation->Action.type == PRIORITY_ACTION_CHANGE );
-    _Priority_Plain_changed(
-      &priority_queue->Queue,
-      &scheduler_node->Wait.Priority.Node
-    );
+    switch ( priority_action_type ) {
+#if defined(RTEMS_SMP)
+      case PRIORITY_ACTION_ADD:
+        _Priority_Plain_insert(
+          &priority_queue->Queue,
+          &scheduler_node->Wait.Priority.Node,
+          _Priority_Get_priority( &scheduler_node->Wait.Priority )
+        );
+        break;
+      case PRIORITY_ACTION_REMOVE:
+        _Priority_Plain_extract(
+          &priority_queue->Queue,
+          &scheduler_node->Wait.Priority.Node
+        );
+        break;
+#endif
+      default:
+        _Assert( priority_action_type == PRIORITY_ACTION_CHANGE );
+        _Priority_Plain_changed(
+          &priority_queue->Queue,
+          &scheduler_node->Wait.Priority.Node
+        );
+        break;
+    }
 
     priority_aggregation = _Priority_Get_next_action( priority_aggregation );
   } while ( _Priority_Actions_is_valid( priority_aggregation ) );
@@ -312,18 +395,38 @@ static void _Thread_queue_Priority_do_initialize(
 {
   Scheduler_Node              *scheduler_node;
   Thread_queue_Priority_queue *priority_queue;
-
-  scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
-  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
-
 #if defined(RTEMS_SMP)
-  _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
+  Chain_Node                  *wait_node;
+  const Chain_Node            *wait_tail;
 #endif
 
+  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
+  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+
   _Priority_Initialize_one(
     &priority_queue->Queue,
     &scheduler_node->Wait.Priority.Node
   );
+
+#if defined(RTEMS_SMP)
+  _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
+
+  wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
+
+  while ( wait_node != wait_tail ) {
+    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
+    priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+
+    _Priority_Initialize_one(
+      &priority_queue->Queue,
+      &scheduler_node->Wait.Priority.Node
+    );
+    _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
+
+    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+  }
+#endif
 }
 
 static void _Thread_queue_Priority_do_enqueue(
@@ -333,28 +436,49 @@ static void _Thread_queue_Priority_do_enqueue(
   Thread_queue_Heads   *heads
 )
 {
+#if defined(RTEMS_SMP)
+  Chain_Node       *wait_node;
+  const Chain_Node *wait_tail;
+
+  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
+  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
+
+  do {
+    Scheduler_Node              *scheduler_node;
+    Thread_queue_Priority_queue *priority_queue;
+
+    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
+    priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+
+    if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
+      _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
+      _Priority_Initialize_one(
+        &priority_queue->Queue,
+        &scheduler_node->Wait.Priority.Node
+      );
+    } else {
+      _Priority_Plain_insert(
+        &priority_queue->Queue,
+        &scheduler_node->Wait.Priority.Node,
+        _Priority_Get_priority( &scheduler_node->Wait.Priority )
+      );
+    }
+
+    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+  } while ( wait_node != wait_tail );
+#else
   Scheduler_Node              *scheduler_node;
   Thread_queue_Priority_queue *priority_queue;
 
-  scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
+  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
   priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
 
-#if defined(RTEMS_SMP)
-  if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
-    _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
-    _Priority_Initialize_one(
-      &priority_queue->Queue,
-      &scheduler_node->Wait.Priority.Node
-    );
-    return;
-  }
-#endif
-
   _Priority_Plain_insert(
     &priority_queue->Queue,
     &scheduler_node->Wait.Priority.Node,
     _Priority_Get_priority( &scheduler_node->Wait.Priority )
   );
+#endif
 }
 
 static void _Thread_queue_Priority_do_extract(
@@ -365,27 +489,64 @@ static void _Thread_queue_Priority_do_extract(
   Thread_Control       *the_thread
 )
 {
+#if defined(RTEMS_SMP)
+  Chain_Node       *wait_node;
+  const Chain_Node *wait_tail;
+
+  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
+  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
+
+  do {
+    Scheduler_Node              *scheduler_node;
+    Thread_queue_Priority_queue *priority_queue;
+
+    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
+    priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+
+    _Priority_Plain_extract(
+      &priority_queue->Queue,
+      &scheduler_node->Wait.Priority.Node
+    );
+
+    if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
+      _Chain_Extract_unprotected( &priority_queue->Node );
+    }
+
+    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+  } while ( wait_node != wait_tail );
+#else
   Scheduler_Node              *scheduler_node;
   Thread_queue_Priority_queue *priority_queue;
 
-  (void) current_or_previous_owner;
-  (void) queue_context;
-
-  scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
+  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
   priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
 
   _Priority_Plain_extract(
     &priority_queue->Queue,
     &scheduler_node->Wait.Priority.Node
   );
+#endif
 
-#if defined(RTEMS_SMP)
-  _Chain_Extract_unprotected( &priority_queue->Node );
+  (void) current_or_previous_owner;
+  (void) queue_context;
+}
 
-  if ( !_Priority_Is_empty( &priority_queue->Queue ) ) {
-    _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
-  }
-#endif
+static void _Thread_queue_Priority_do_surrender(
+  Thread_queue_Queue   *queue,
+  Thread_queue_Heads   *heads,
+  Thread_Control       *current_or_previous_owner,
+  Thread_queue_Context *queue_context,
+  Thread_Control       *the_thread
+)
+{
+  _Thread_queue_Priority_queue_rotation( heads );
+  _Thread_queue_Priority_do_extract(
+    queue,
+    heads,
+    current_or_previous_owner,
+    queue_context,
+    the_thread
+  );
 }
 
 static void _Thread_queue_Priority_enqueue(
@@ -458,33 +619,78 @@ static Thread_Control *_Thread_queue_Priority_surrender(
     NULL,
     queue_context,
     first,
-    _Thread_queue_Priority_do_extract
+    _Thread_queue_Priority_do_surrender
   );
 
   return first;
 }
 
-static void _Thread_queue_Priority_inherit_do_actions_change(
+static void _Thread_queue_Priority_inherit_do_priority_actions_action(
+  Priority_Aggregation *priority_aggregation,
+  Priority_Actions     *priority_actions,
+  Scheduler_Node       *scheduler_node_of_owner,
+  Priority_Action_type  priority_action_type
+)
+{
+  _Priority_Set_action(
+    &scheduler_node_of_owner->Wait.Priority,
+    &priority_aggregation->Node,
+    priority_action_type
+  );
+  _Priority_Actions_add(
+    priority_actions,
+    &scheduler_node_of_owner->Wait.Priority
+  );
+}
+
+#if defined(RTEMS_SMP)
+static void _Thread_queue_Priority_inherit_do_priority_actions_add(
   Priority_Aggregation *priority_aggregation,
-  bool                  prepend_it,
   Priority_Actions     *priority_actions,
   void                 *arg
 )
 {
-  Thread_queue_Priority_queue *priority_queue;
-  Scheduler_Node              *scheduler_node;
+  _Thread_queue_Priority_inherit_do_priority_actions_action(
+    priority_aggregation,
+    priority_actions,
+    arg,
+    PRIORITY_ACTION_ADD
+  );
+}
 
-  priority_queue = THREAD_QUEUE_PRIORITY_QUEUE_OF_PRIORITY_AGGREGATION(
-    priority_aggregation
+static void _Thread_queue_Priority_inherit_do_priority_actions_remove(
+  Priority_Aggregation *priority_aggregation,
+  Priority_Actions     *priority_actions,
+  void                 *arg
+)
+{
+  _Thread_queue_Priority_queue_extract(
+    priority_aggregation,
+    priority_actions,
+    arg
+  );
+  _Thread_queue_Priority_inherit_do_priority_actions_action(
+    priority_aggregation,
+    priority_actions,
+    arg,
+    PRIORITY_ACTION_REMOVE
   );
-  scheduler_node = priority_queue->scheduler_node;
+}
+#endif
 
-  _Priority_Set_action(
-    &scheduler_node->Wait.Priority,
-    &priority_aggregation->Node,
+static void _Thread_queue_Priority_inherit_do_priority_actions_change(
+  Priority_Aggregation *priority_aggregation,
+  bool                  prepend_it,
+  Priority_Actions     *priority_actions,
+  void                 *arg
+)
+{
+  _Thread_queue_Priority_inherit_do_priority_actions_action(
+    priority_aggregation,
+    priority_actions,
+    arg,
     PRIORITY_ACTION_CHANGE
   );
-  _Priority_Actions_add( priority_actions, &scheduler_node->Wait.Priority );
 }
 
 static void _Thread_queue_Priority_inherit_priority_actions(
@@ -493,83 +699,84 @@ static void _Thread_queue_Priority_inherit_priority_actions(
 )
 {
   Thread_queue_Heads   *heads;
+  Thread_Control       *owner;
   Priority_Aggregation *priority_aggregation;
 
   heads = queue->heads;
   _Assert( heads != NULL );
 
+  owner = queue->owner;
+  _Assert( owner != NULL );
+
   _Assert( !_Priority_Actions_is_empty( priority_actions ) );
   priority_aggregation = _Priority_Actions_move( priority_actions );
 
   do {
     Priority_Aggregation        *next_aggregation;
     Scheduler_Node              *scheduler_node;
+    size_t                       scheduler_index;
     Thread_queue_Priority_queue *priority_queue;
+    Scheduler_Node              *scheduler_node_of_owner;
+    Priority_Action_type         priority_action_type;
 
     next_aggregation = _Priority_Get_next_action( priority_aggregation );
 
     scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
-    priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
-
-    _Assert( priority_aggregation->Action.type == PRIORITY_ACTION_CHANGE );
-    _Priority_Changed(
-      &priority_queue->Queue,
-      &scheduler_node->Wait.Priority.Node,
-      false,
-      priority_actions,
-      _Thread_queue_Priority_inherit_do_actions_change,
-      NULL
+    scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
+    priority_queue = _Thread_queue_Priority_queue_by_index(
+      heads,
+      scheduler_index
     );
+    scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
+      owner,
+      scheduler_index
+    );
+    priority_action_type = priority_aggregation->Action.type;
 
-    priority_aggregation = next_aggregation;
-  } while ( _Priority_Actions_is_valid( priority_aggregation ) );
-}
-
-static void _Thread_queue_Boost_priority(
-  Thread_queue_Heads   *heads,
-  Thread_Control       *the_thread,
-  Thread_Control       *owner,
-  Thread_queue_Context *queue_context
-)
-{
+    switch ( priority_action_type ) {
 #if defined(RTEMS_SMP)
-  const Scheduler_Control *scheduler;
-  const Scheduler_Control *scheduler_of_owner;
-  Scheduler_Node          *scheduler_node_of_owner;
-  Priority_Control         boost_priority;
-
-  if ( _Priority_Node_is_active( &heads->Boost_priority ) ) {
-    return;
-  }
-
-  scheduler = _Scheduler_Get_own( the_thread );
-  scheduler_of_owner = _Scheduler_Get_own( owner );
-
-  if ( scheduler == scheduler_of_owner ) {
-    return;
-  }
-
-  scheduler_node_of_owner = _Thread_Scheduler_get_own_node( owner );
-
-  boost_priority = _Scheduler_Map_priority(
-    scheduler_of_owner,
-    PRIORITY_PSEUDO_ISR
-  );
-
-  _Priority_Node_initialize( &heads->Boost_priority, boost_priority );
-  _Priority_Actions_initialize_one(
-    &queue_context->Priority.Actions,
-    &scheduler_node_of_owner->Wait.Priority,
-    &heads->Boost_priority,
-    PRIORITY_ACTION_ADD
-  );
-  _Thread_Priority_perform_actions( owner, queue_context );
-#else
-  (void) heads;
-  (void) the_thread;
-  (void) owner;
-  (void) queue_context;
+      case PRIORITY_ACTION_ADD:
+        if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
+          _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
+          priority_queue->scheduler_node = scheduler_node_of_owner;
+        }
+
+        _Priority_Insert(
+          &priority_queue->Queue,
+          &scheduler_node->Wait.Priority.Node,
+          priority_actions,
+          _Thread_queue_Priority_inherit_do_priority_actions_add,
+          _Thread_queue_Priority_inherit_do_priority_actions_change,
+          scheduler_node_of_owner
+        );
+        break;
+      case PRIORITY_ACTION_REMOVE:
+        _Priority_Extract(
+          &priority_queue->Queue,
+          &scheduler_node->Wait.Priority.Node,
+          priority_actions,
+          _Thread_queue_Priority_inherit_do_priority_actions_remove,
+          _Thread_queue_Priority_inherit_do_priority_actions_change,
+          scheduler_node_of_owner
+        );
+
+        break;
 #endif
+      default:
+        _Assert( priority_action_type == PRIORITY_ACTION_CHANGE );
+        _Priority_Changed(
+          &priority_queue->Queue,
+          &scheduler_node->Wait.Priority.Node,
+          false,
+          priority_actions,
+          _Thread_queue_Priority_inherit_do_priority_actions_change,
+          scheduler_node_of_owner
+        );
+        break;
+    }
+
+    priority_aggregation = next_aggregation;
+  } while ( _Priority_Actions_is_valid( priority_aggregation ) );
 }
 
 static void _Thread_queue_Priority_inherit_do_initialize(
@@ -580,43 +787,103 @@ static void _Thread_queue_Priority_inherit_do_initialize(
 )
 {
   Scheduler_Node              *scheduler_node;
+  size_t                       scheduler_index;
   Thread_queue_Priority_queue *priority_queue;
   Thread_Control              *owner;
   Scheduler_Node              *scheduler_node_of_owner;
-
-  scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
-  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
-
 #if defined(RTEMS_SMP)
-  _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
+  Chain_Node                  *wait_node;
+  const Chain_Node            *wait_tail;
 #endif
 
+  owner = queue->owner;
+
+  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
+  scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
+  priority_queue = _Thread_queue_Priority_queue_by_index(
+    heads,
+    scheduler_index
+  );
+  scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
+    owner,
+    scheduler_index
+  );
+
+  priority_queue->scheduler_node = scheduler_node_of_owner;
   _Priority_Initialize_one(
     &priority_queue->Queue,
     &scheduler_node->Wait.Priority.Node
   );
-
-  owner = queue->owner;
-  scheduler_node_of_owner = _Thread_Scheduler_get_own_node( owner );
-  priority_queue->scheduler_node = scheduler_node_of_owner;
-
   _Priority_Actions_initialize_one(
     &queue_context->Priority.Actions,
     &scheduler_node_of_owner->Wait.Priority,
     &priority_queue->Queue.Node,
     PRIORITY_ACTION_ADD
   );
-  _Thread_Priority_perform_actions( owner, queue_context );
-  _Thread_queue_Boost_priority( heads, the_thread, owner, queue_context );
-}
 
-static void _Thread_queue_Priority_inherit_do_enqueue_change(
-  Priority_Aggregation *priority_aggregation,
-  bool                  prepend_it,
-  Priority_Actions     *priority_actions,
+#if defined(RTEMS_SMP)
+  _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
+
+  wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
+
+  while ( wait_node != wait_tail ) {
+    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
+    scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
+    priority_queue = _Thread_queue_Priority_queue_by_index(
+      heads,
+      scheduler_index
+    );
+    scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
+      owner,
+      scheduler_index
+    );
+
+    _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
+    priority_queue->scheduler_node = scheduler_node_of_owner;
+    _Priority_Initialize_one(
+      &priority_queue->Queue,
+      &scheduler_node->Wait.Priority.Node
+    );
+    _Priority_Set_action(
+      &scheduler_node_of_owner->Wait.Priority,
+      &priority_queue->Queue.Node,
+      PRIORITY_ACTION_ADD
+    );
+    _Priority_Actions_add(
+      &queue_context->Priority.Actions,
+      &scheduler_node_of_owner->Wait.Priority
+    );
+
+    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+  }
+#endif
+
+  _Thread_Priority_perform_actions( owner, queue_context );
+}
+
+static void _Thread_queue_Priority_inherit_do_enqueue_change(
+  Priority_Aggregation *priority_aggregation,
+  bool                  prepend_it,
+  Priority_Actions     *priority_actions,
   void                 *arg
 )
 {
+#if defined(RTEMS_SMP)
+  Scheduler_Node *scheduler_node_of_owner;
+
+  scheduler_node_of_owner = arg;
+
+  _Priority_Set_action(
+    &scheduler_node_of_owner->Wait.Priority,
+    &priority_aggregation->Node,
+    PRIORITY_ACTION_CHANGE
+  );
+  _Priority_Actions_add(
+    priority_actions,
+    &scheduler_node_of_owner->Wait.Priority
+  );
+#else
   Thread_queue_Queue   *queue;
   Thread_Control       *owner;
   Scheduler_Node       *scheduler_node_of_owner;
@@ -634,6 +901,7 @@ static void _Thread_queue_Priority_inherit_do_enqueue_change(
     PRIORITY_ACTION_CHANGE
   );
   _Thread_Priority_perform_actions( owner, queue_context );
+#endif
 }
 
 static void _Thread_queue_Priority_inherit_do_enqueue(
@@ -643,38 +911,72 @@ static void _Thread_queue_Priority_inherit_do_enqueue(
   Thread_queue_Heads   *heads
 )
 {
-  Scheduler_Node              *scheduler_node;
-  Thread_queue_Priority_queue *priority_queue;
-
-  scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
-  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
-
 #if defined(RTEMS_SMP)
-  if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
-    Thread_Control *owner;
-    Scheduler_Node *scheduler_node_of_owner;
+  Thread_Control   *owner;
+  Chain_Node       *wait_node;
+  const Chain_Node *wait_tail;
 
-    _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
-    _Priority_Initialize_one(
-      &priority_queue->Queue,
-      &scheduler_node->Wait.Priority.Node
-    );
+  owner = queue->owner;
+  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
+  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
 
-    owner = queue->owner;
-    scheduler_node_of_owner = _Thread_Scheduler_get_own_node( owner );
-    priority_queue->scheduler_node = scheduler_node_of_owner;
+  _Priority_Actions_initialize_empty( &queue_context->Priority.Actions );
 
-    _Priority_Actions_initialize_one(
-      &queue_context->Priority.Actions,
-      &scheduler_node_of_owner->Wait.Priority,
-      &priority_queue->Queue.Node,
-      PRIORITY_ACTION_ADD
+  do {
+    Scheduler_Node              *scheduler_node;
+    size_t                       scheduler_index;
+    Thread_queue_Priority_queue *priority_queue;
+    Scheduler_Node              *scheduler_node_of_owner;
+
+    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
+    scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
+    priority_queue = _Thread_queue_Priority_queue_by_index(
+      heads,
+      scheduler_index
     );
+    scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
+      owner,
+      scheduler_index
+    );
+
+    if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
+      _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
+      priority_queue->scheduler_node = scheduler_node_of_owner;
+      _Priority_Initialize_one(
+        &priority_queue->Queue,
+        &scheduler_node->Wait.Priority.Node
+      );
+      _Priority_Set_action(
+        &scheduler_node_of_owner->Wait.Priority,
+        &priority_queue->Queue.Node,
+        PRIORITY_ACTION_ADD
+      );
+      _Priority_Actions_add(
+        &queue_context->Priority.Actions,
+        &scheduler_node_of_owner->Wait.Priority
+      );
+    } else {
+      _Priority_Non_empty_insert(
+        &priority_queue->Queue,
+        &scheduler_node->Wait.Priority.Node,
+        &queue_context->Priority.Actions,
+        _Thread_queue_Priority_inherit_do_enqueue_change,
+        scheduler_node_of_owner
+      );
+    }
+
+    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+  } while ( wait_node != wait_tail );
+
+  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
     _Thread_Priority_perform_actions( owner, queue_context );
-    _Thread_queue_Boost_priority( heads, the_thread, owner, queue_context );
-    return;
   }
-#endif
+#else
+  Scheduler_Node              *scheduler_node;
+  Thread_queue_Priority_queue *priority_queue;
+
+  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
+  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
 
   _Priority_Non_empty_insert(
     &priority_queue->Queue,
@@ -683,12 +985,7 @@ static void _Thread_queue_Priority_inherit_do_enqueue(
     _Thread_queue_Priority_inherit_do_enqueue_change,
     queue
   );
-  _Thread_queue_Boost_priority(
-    heads,
-    the_thread,
-    queue->owner,
-    queue_context
-  );
+#endif
 }
 
 static void _Thread_queue_Priority_inherit_enqueue(
@@ -708,24 +1005,42 @@ static void _Thread_queue_Priority_inherit_enqueue(
 
 static void _Thread_queue_Priority_inherit_do_extract_action(
   Priority_Actions     *priority_actions,
-  Thread_Control       *owner,
-  Priority_Node        *priority_action_node,
+  void                 *arg,
+  Priority_Aggregation *priority_aggregation,
   Priority_Action_type  priority_action_type
 )
 {
+#if defined(RTEMS_SMP)
+  Scheduler_Node *scheduler_node_of_owner;
+
+  scheduler_node_of_owner = arg;
+
+  _Priority_Set_action(
+    &scheduler_node_of_owner->Wait.Priority,
+    &priority_aggregation->Node,
+    priority_action_type
+  );
+  _Priority_Actions_add(
+    priority_actions,
+    &scheduler_node_of_owner->Wait.Priority
+  );
+#else
   Thread_queue_Context *queue_context;
+  Thread_Control       *owner;
   Scheduler_Node       *scheduler_node_of_owner;
 
   queue_context = THREAD_QUEUE_CONTEXT_OF_PRIORITY_ACTIONS( priority_actions );
-  scheduler_node_of_owner = _Thread_Scheduler_get_own_node( owner );
+  owner = arg;
+  scheduler_node_of_owner = _Thread_Scheduler_get_home_node( owner );
 
   _Priority_Actions_initialize_one(
     &queue_context->Priority.Actions,
     &scheduler_node_of_owner->Wait.Priority,
-    priority_action_node,
+    &priority_aggregation->Node,
     priority_action_type
   );
-  _Thread_Priority_perform_actions( owner, queue_context );
+  _Thread_Priority_perform_actions( arg, queue_context );
+#endif
 }
 
 static void _Thread_queue_Priority_inherit_do_extract_remove(
@@ -737,7 +1052,7 @@ static void _Thread_queue_Priority_inherit_do_extract_remove(
   _Thread_queue_Priority_inherit_do_extract_action(
     priority_actions,
     arg,
-    &priority_aggregation->Node,
+    priority_aggregation,
     PRIORITY_ACTION_REMOVE
   );
 }
@@ -752,7 +1067,7 @@ static void _Thread_queue_Priority_inherit_do_extract_change(
   _Thread_queue_Priority_inherit_do_extract_action(
     priority_actions,
     arg,
-    &priority_aggregation->Node,
+    priority_aggregation,
     PRIORITY_ACTION_CHANGE
   );
 }
@@ -765,13 +1080,56 @@ static void _Thread_queue_Priority_inherit_do_extract(
   Thread_Control       *the_thread
 )
 {
+#if defined(RTEMS_SMP)
+  Chain_Node                  *wait_node;
+  const Chain_Node            *wait_tail;
+#endif
   Scheduler_Node              *scheduler_node;
   Thread_queue_Priority_queue *priority_queue;
 
-  scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
-  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+#if defined(RTEMS_SMP)
+  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
+  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
 
-  _Thread_queue_Path_acquire_critical( queue, the_thread, queue_context );
+  _Priority_Actions_initialize_empty( &queue_context->Priority.Actions );
+
+  do {
+    size_t          scheduler_index;
+    Scheduler_Node *scheduler_node_of_owner;
+
+    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
+    scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
+    priority_queue = _Thread_queue_Priority_queue_by_index(
+      heads,
+      scheduler_index
+    );
+    scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
+      owner,
+      scheduler_index
+    );
+
+    _Priority_Extract(
+      &priority_queue->Queue,
+      &scheduler_node->Wait.Priority.Node,
+      &queue_context->Priority.Actions,
+      _Thread_queue_Priority_inherit_do_extract_remove,
+      _Thread_queue_Priority_inherit_do_extract_change,
+      scheduler_node_of_owner
+    );
+
+    if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
+      _Chain_Extract_unprotected( &priority_queue->Node );
+    }
+
+    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+  } while ( wait_node != wait_tail );
+
+  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
+    _Thread_Priority_perform_actions( owner, queue_context );
+  }
+#else
+  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
+  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
 
   _Priority_Extract(
     &priority_queue->Queue,
@@ -781,30 +1139,7 @@ static void _Thread_queue_Priority_inherit_do_extract(
     _Thread_queue_Priority_inherit_do_extract_change,
     owner
   );
-
-#if defined(RTEMS_SMP)
-  _Chain_Extract_unprotected( &priority_queue->Node );
-
-  if ( !_Priority_Is_empty( &priority_queue->Queue ) ) {
-    _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
-  }
-
-  if (
-    _Priority_Node_is_active( &heads->Boost_priority )
-      && ( _Chain_Is_empty( &heads->Heads.Fifo )
-        || _Chain_Has_only_one_node( &heads->Heads.Fifo ) )
-  ) {
-    _Thread_queue_Priority_inherit_do_extract_action(
-      &queue_context->Priority.Actions,
-      owner,
-      &heads->Boost_priority,
-      PRIORITY_ACTION_REMOVE
-    );
-    _Priority_Node_set_inactive( &heads->Boost_priority );
-  }
 #endif
-
-  _Thread_queue_Path_release_critical( queue_context );
 }
 
 static void _Thread_queue_Priority_inherit_extract(
@@ -813,6 +1148,38 @@ static void _Thread_queue_Priority_inherit_extract(
   Thread_queue_Context *queue_context
 )
 {
+#if defined(RTEMS_SMP)
+  /*
+   * We must lock the thread wait path for the complete extract operation
+   * including the thread queue head management.  Consider the following
+   * scenario on three processors.  Thread T0 owns thread queue A, thread T1
+   * owns thread queue B and thread T2 owns thread queue C.  Thread T0 waits
+   * for B and thread T1 waits for C.
+   *
+   * A <-------------------------\
+   *  \                          |
+   *   > T0 -> B                 |
+   *            \                |
+   *             > T1 -> C       |
+   *                      \      |
+   *                       > T2 -/
+   *
+   * Now three things happen at the same time
+   *  - thread T0 times out,
+   *  - thread T1 times out,
+   *  - thread T2 tries to enqueue on a thread queue A.
+   *
+   * Thread T1 acquires thread queue lock C and waits for thread queue lock A.
+   * Thread T2 acquires thread queue lock A and waits for thread queue lock B.
+   * Thread T0 acquires thread queue lock B and detects a potential deadlock.
+   * Thread T0 carries out the thread queue extraction due to the timeout and
+   * uses the thread wait path segments acquired by thread T1 and T2.  This
+   * resolves the deadlock.  Thread T1 and T2 can the complete their
+   * operations.
+   */
+  _Thread_queue_Path_acquire_critical( queue, the_thread, queue_context );
+#endif
+
   _Thread_queue_Queue_extract(
     queue,
     queue->heads,
@@ -821,7 +1188,50 @@ static void _Thread_queue_Priority_inherit_extract(
     the_thread,
     _Thread_queue_Priority_inherit_do_extract
   );
+
+#if defined(RTEMS_SMP)
+  _Thread_queue_Path_release_critical( queue_context );
+#endif
+}
+
+#if defined(RTEMS_SMP)
+static void _Thread_queue_Priority_inherit_do_surrender_add(
+  Priority_Aggregation *priority_aggregation,
+  Priority_Actions     *priority_actions,
+  void                 *arg
+)
+{
+  Scheduler_Node *scheduler_node;
+  Thread_Control *the_thread;
+
+  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
+  the_thread = arg;
+
+  _Chain_Append_unprotected(
+    &the_thread->Scheduler.Wait_nodes,
+    &scheduler_node->Thread.Wait_node
+  );
+  _Scheduler_Node_set_priority(
+    scheduler_node,
+    _Priority_Get_priority( priority_aggregation ),
+    false
+  );
+}
+
+static void _Thread_queue_Priority_inherit_do_surrender_remove(
+  Priority_Aggregation *priority_aggregation,
+  Priority_Actions     *priority_actions,
+  void                 *arg
+)
+{
+  Scheduler_Node *scheduler_node;
+
+  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
+
+  _Priority_Actions_add( priority_actions, priority_aggregation );
+  _Chain_Extract_unprotected( &scheduler_node->Thread.Wait_node );
 }
+#endif
 
 static void _Thread_queue_Priority_inherit_do_surrender_change(
   Priority_Aggregation *priority_aggregation,
@@ -830,10 +1240,14 @@ static void _Thread_queue_Priority_inherit_do_surrender_change(
   void                 *arg
 )
 {
+#if defined(RTEMS_SMP)
+  _Priority_Actions_add( priority_actions, priority_aggregation );
+#else
   _Thread_queue_Context_add_priority_update(
     THREAD_QUEUE_CONTEXT_OF_PRIORITY_ACTIONS( priority_actions ),
     arg
   );
+#endif
   _Scheduler_Node_set_priority(
     SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation ),
     _Priority_Get_priority( priority_aggregation ),
@@ -841,35 +1255,17 @@ static void _Thread_queue_Priority_inherit_do_surrender_change(
   );
 }
 
-static void _Thread_queue_Priority_add(
-  Thread_Control       *the_thread,
+static void _Thread_queue_Priority_inherit_do_surrender_change_2(
   Priority_Aggregation *priority_aggregation,
-  Priority_Node        *priority_node,
-  Thread_queue_Context *queue_context
-)
-{
-  _Priority_Non_empty_insert(
-    priority_aggregation,
-    priority_node,
-    &queue_context->Priority.Actions,
-    _Thread_queue_Priority_inherit_do_surrender_change,
-    the_thread
-  );
-}
-
-static void _Thread_queue_Priority_remove(
-  Thread_Control       *the_thread,
-  Scheduler_Node       *scheduler_node,
-  Priority_Node        *priority_node,
-  Thread_queue_Context *queue_context
+  bool                  prepend_it,
+  Priority_Actions     *priority_actions,
+  void                 *arg
 )
 {
-  _Priority_Extract_non_empty(
-    &scheduler_node->Wait.Priority,
-    priority_node,
-    &queue_context->Priority.Actions,
-    _Thread_queue_Priority_inherit_do_surrender_change,
-    the_thread
+  _Scheduler_Node_set_priority(
+    SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation ),
+    _Priority_Get_priority( priority_aggregation ),
+    prepend_it
   );
 }
 
@@ -881,78 +1277,141 @@ static void _Thread_queue_Priority_inherit_do_surrender(
   Thread_Control       *the_thread
 )
 {
+#if defined(RTEMS_SMP)
+  Chain_Node                  *fifo_node;
+  const Chain_Node            *fifo_head;
+  const Chain_Node            *fifo_tail;
+  Chain_Node                  *wait_node;
+  const Chain_Node            *wait_tail;
+  ISR_lock_Context             lock_context;
+#endif
   Scheduler_Node              *scheduler_node;
   Thread_queue_Priority_queue *priority_queue;
-  ISR_lock_Context             lock_context;
+  Scheduler_Node              *scheduler_node_of_owner;
 
-  scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
-  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+#if defined(RTEMS_SMP)
+  /*
+   * Remove the priority node of each priority queue from the previous owner.
+   * If a priority changes due to this, then register it for a priority update.
+   */
+
+  fifo_node = _Thread_queue_Priority_queue_rotation( heads );
+  fifo_head = _Chain_Immutable_head( &heads->Heads.Fifo );
+
+  _Priority_Actions_initialize_empty( &queue_context->Priority.Actions );
 
   _Thread_Wait_acquire_default_critical( previous_owner, &lock_context );
 
-#if defined(RTEMS_SMP)
-  if ( _Priority_Node_is_active( &heads->Boost_priority ) ) {
-    _Thread_queue_Priority_remove(
-      previous_owner,
-      _Thread_Scheduler_get_own_node( previous_owner ),
-      &heads->Boost_priority,
-      queue_context
+  do {
+    priority_queue = (Thread_queue_Priority_queue *) fifo_node;
+    scheduler_node_of_owner = priority_queue->scheduler_node;
+
+    _Assert( scheduler_node_of_owner->owner == previous_owner );
+
+    _Priority_Extract(
+      &scheduler_node_of_owner->Wait.Priority,
+      &priority_queue->Queue.Node,
+      &queue_context->Priority.Actions,
+      _Thread_queue_Priority_inherit_do_surrender_remove,
+      _Thread_queue_Priority_inherit_do_surrender_change,
+      NULL
     );
-    _Priority_Node_set_inactive( &heads->Boost_priority );
-  }
-#endif
 
-  _Thread_queue_Priority_remove(
-    previous_owner,
-    priority_queue->scheduler_node,
-    &priority_queue->Queue.Node,
-    queue_context
-  );
+    fifo_node = _Chain_Previous( fifo_node );
+  } while ( fifo_node != fifo_head );
+
+  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
+    /*
+     * The previous owner performs this surrender operation.  So, it is
+     * definitely not enqueued on a thread queue.  It is sufficient to notify
+     * the scheduler about a priority update.  There is no need for a
+     * _Thread_Priority_perform_actions().
+     */
+    _Thread_queue_Context_add_priority_update( queue_context, previous_owner );
+  }
 
   _Thread_Wait_release_default_critical( previous_owner, &lock_context );
 
+  /*
+   * Remove the wait node of the new owner from the corresponding priority
+   * queue.
+   */
+
+  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
+  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
+
+  do {
+    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
+    priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+
+    _Priority_Extract(
+      &priority_queue->Queue,
+      &scheduler_node->Wait.Priority.Node,
+      NULL,
+      _Thread_queue_Priority_queue_extract,
+      _Priority_Change_nothing,
+      NULL
+    );
+
+    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
+  } while ( wait_node != wait_tail );
+
+  /* Add the priority node of the remaining priority queues to the new owner */
+
+  fifo_node = _Chain_First( &heads->Heads.Fifo );
+  fifo_tail = _Chain_Immutable_tail( &heads->Heads.Fifo );
+
+  while ( fifo_node != fifo_tail ) {
+    const Scheduler_Control *scheduler;
+
+    priority_queue = (Thread_queue_Priority_queue *) fifo_node;
+    scheduler = _Priority_Get_scheduler( &priority_queue->Queue );
+    scheduler_node = _Thread_Scheduler_get_node_by_index(
+      the_thread,
+      _Scheduler_Get_index( scheduler )
+    );
+
+    priority_queue->scheduler_node = scheduler_node;
+    _Priority_Insert(
+      &scheduler_node->Wait.Priority,
+      &priority_queue->Queue.Node,
+      &queue_context->Priority.Actions,
+      _Thread_queue_Priority_inherit_do_surrender_add,
+      _Thread_queue_Priority_inherit_do_surrender_change_2,
+      the_thread
+    );
+
+    fifo_node = _Chain_Next( fifo_node );
+  }
+#else
+  scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
+  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
+  scheduler_node_of_owner = priority_queue->scheduler_node;
+
+  _Priority_Extract_non_empty(
+    &scheduler_node_of_owner->Wait.Priority,
+    &priority_queue->Queue.Node,
+    &queue_context->Priority.Actions,
+    _Thread_queue_Priority_inherit_do_surrender_change,
+    previous_owner
+  );
   _Priority_Extract(
     &priority_queue->Queue,
     &scheduler_node->Wait.Priority.Node,
     NULL,
     _Priority_Remove_nothing,
     _Priority_Change_nothing,
-    previous_owner
+    NULL
   );
 
   if ( !_Priority_Is_empty( &priority_queue->Queue ) ) {
     priority_queue->scheduler_node = scheduler_node;
-    _Thread_queue_Priority_add(
-      the_thread,
+    _Priority_Non_empty_insert(
       &scheduler_node->Wait.Priority,
       &priority_queue->Queue.Node,
-      queue_context
-    );
-  }
-
-#if defined(RTEMS_SMP)
-  _Chain_Extract_unprotected( &priority_queue->Node );
-
-  if ( !_Priority_Is_empty( &priority_queue->Queue ) ) {
-    _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
-  }
-
-  if (
-    !_Chain_Is_empty( &heads->Heads.Fifo)
-      && !_Chain_Has_only_one_node( &heads->Heads.Fifo)
-  ) {
-    Priority_Control boost_priority;
-
-    boost_priority = _Scheduler_Map_priority(
-      _Scheduler_Get_own( the_thread ),
-      PRIORITY_PSEUDO_ISR
-    );
-    _Priority_Node_initialize( &heads->Boost_priority, boost_priority );
-    _Thread_queue_Priority_add(
-      the_thread,
-      &scheduler_node->Wait.Priority,
-      &heads->Boost_priority,
-      queue_context
+      &queue_context->Priority.Actions,
+      _Thread_queue_Priority_inherit_do_surrender_change,
+      the_thread
     );
   }
 #endif
diff --git a/testsuites/smptests/smpmutex01/init.c b/testsuites/smptests/smpmutex01/init.c
index d88b7b8..f595755 100644
--- a/testsuites/smptests/smpmutex01/init.c
+++ b/testsuites/smptests/smpmutex01/init.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 embedded brains GmbH.  All rights reserved.
+ * Copyright (c) 2015, 2016 embedded brains GmbH.  All rights reserved.
  *
  *  embedded brains GmbH
  *  Dornierstr. 4
@@ -28,11 +28,21 @@ const char rtems_test_name[] = "SMPMUTEX 1";
 
 #define TASK_COUNT 9
 
+#define PRIO_NONE 0
+
+/* Value choosen for Qemu, 2 would be sufficient for real targets */
+#define TIMEOUT_IN_TICKS 10
+
 typedef enum {
   REQ_WAKE_UP_MASTER = RTEMS_EVENT_0,
   REQ_WAKE_UP_HELPER = RTEMS_EVENT_1,
   REQ_MTX_OBTAIN = RTEMS_EVENT_2,
-  REQ_MTX_RELEASE = RTEMS_EVENT_3
+  REQ_MTX_OBTAIN_TIMEOUT = RTEMS_EVENT_3,
+  REQ_MTX_RELEASE = RTEMS_EVENT_4,
+  REQ_MTX_2_OBTAIN = RTEMS_EVENT_5,
+  REQ_MTX_2_RELEASE = RTEMS_EVENT_6,
+  REQ_SEM_OBTAIN_RELEASE = RTEMS_EVENT_7,
+  REQ_SEM_RELEASE = RTEMS_EVENT_8
 } request_id;
 
 typedef enum {
@@ -50,6 +60,8 @@ typedef enum {
 
 typedef struct {
   rtems_id mtx;
+  rtems_id mtx_2;
+  rtems_id sem;
   rtems_id tasks[TASK_COUNT];
   int generation[TASK_COUNT];
   int expected_generation[TASK_COUNT];
@@ -156,6 +168,14 @@ static void obtain(test_context *ctx)
   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
 }
 
+static void obtain_timeout(test_context *ctx)
+{
+  rtems_status_code sc;
+
+  sc = rtems_semaphore_obtain(ctx->mtx, RTEMS_WAIT, TIMEOUT_IN_TICKS);
+  rtems_test_assert(sc == RTEMS_TIMEOUT);
+}
+
 static void release(test_context *ctx)
 {
   rtems_status_code sc;
@@ -164,6 +184,46 @@ static void release(test_context *ctx)
   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
 }
 
+static void obtain_2(test_context *ctx)
+{
+  rtems_status_code sc;
+
+  sc = rtems_semaphore_obtain(ctx->mtx_2, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void release_2(test_context *ctx)
+{
+  rtems_status_code sc;
+
+  sc = rtems_semaphore_release(ctx->mtx_2);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void sem_obtain(test_context *ctx)
+{
+  rtems_status_code sc;
+
+  sc = rtems_semaphore_obtain(ctx->sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void sem_release(test_context *ctx)
+{
+  rtems_status_code sc;
+
+  sc = rtems_semaphore_release(ctx->sem);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void wait(void)
+{
+  rtems_status_code sc;
+
+  sc = rtems_task_wake_after(TIMEOUT_IN_TICKS + 1);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+}
+
 static void check_generations(test_context *ctx, task_id a, task_id b)
 {
   size_t i;
@@ -199,14 +259,50 @@ static void assert_prio(
   rtems_test_assert(expected == actual);
 }
 
+static void assert_prio_by_scheduler(
+  test_context *ctx,
+  task_id id,
+  rtems_name scheduler,
+  rtems_task_priority expected
+)
+{
+  rtems_task_priority actual;
+  rtems_status_code sc;
+  rtems_id scheduler_id;
+
+  sc = rtems_scheduler_ident(scheduler, &scheduler_id);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  actual = PRIO_NONE;
+  sc = rtems_task_get_priority(
+    ctx->tasks[id],
+    scheduler_id,
+    &actual
+  );
+
+  if (expected == PRIO_NONE) {
+    rtems_test_assert(sc == RTEMS_NOT_DEFINED);
+  } else {
+    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+  }
+
+  rtems_test_assert(actual == expected);
+}
+
 static void helper(rtems_task_argument arg)
 {
   test_context *ctx = &test_instance;
 
   while (true) {
     rtems_event_set events = wait_for_events();
-    rtems_test_assert(events == REQ_WAKE_UP_HELPER);
-    send_event(ctx, M, REQ_WAKE_UP_MASTER);
+
+    if ((events & REQ_WAKE_UP_HELPER) != 0) {
+      send_event(ctx, M, REQ_WAKE_UP_MASTER);
+    }
+
+    if ((events & REQ_SEM_RELEASE) != 0) {
+      sem_release(ctx);
+    }
   }
 }
 
@@ -223,10 +319,31 @@ static void worker(rtems_task_argument arg)
       ++ctx->generation[id];
     }
 
+    if ((events & REQ_MTX_OBTAIN_TIMEOUT) != 0) {
+      obtain_timeout(ctx);
+      ++ctx->generation[id];
+    }
+
     if ((events & REQ_MTX_RELEASE) != 0) {
       release(ctx);
       ++ctx->generation[id];
     }
+
+    if ((events & REQ_MTX_2_OBTAIN) != 0) {
+      obtain_2(ctx);
+      ++ctx->generation[id];
+    }
+
+    if ((events & REQ_MTX_2_RELEASE) != 0) {
+      release_2(ctx);
+      ++ctx->generation[id];
+    }
+
+    if ((events & REQ_SEM_OBTAIN_RELEASE) != 0) {
+      sem_obtain(ctx);
+      ++ctx->generation[id];
+      sem_release(ctx);
+    }
   }
 }
 
@@ -245,13 +362,31 @@ static void test_init(test_context *ctx)
   start_task(ctx, H_B, helper, 6, SCHED_B);
 
   sc = rtems_semaphore_create(
-    rtems_build_name(' ', 'M', 'T', 'X'),
+    rtems_build_name('M', 'T', 'X', '1'),
     1,
     RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY,
     0,
     &ctx->mtx
   );
   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  sc = rtems_semaphore_create(
+    rtems_build_name('M', 'T', 'X', '2'),
+    1,
+    RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY,
+    0,
+    &ctx->mtx_2
+  );
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  sc = rtems_semaphore_create(
+    rtems_build_name(' ', 'S', 'E', 'M'),
+    0,
+    RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY,
+    0,
+    &ctx->sem
+  );
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
 }
 
 static void test_simple_inheritance(test_context *ctx)
@@ -287,67 +422,254 @@ static void test_dequeue_order_one_scheduler_instance(test_context *ctx)
   check_generations(ctx, A_2_1, NONE);
 }
 
-static void test_simple_boosting(test_context *ctx)
+static void test_mixed_queue_two_scheduler_instances(test_context *ctx)
+{
+  obtain(ctx);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+
+  request(ctx, B_4, REQ_MTX_OBTAIN_TIMEOUT);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
+  check_generations(ctx, NONE, NONE);
+  wait();
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+  check_generations(ctx, B_4, NONE);
+
+  request(ctx, B_4, REQ_MTX_OBTAIN);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
+  check_generations(ctx, NONE, NONE);
+
+  request(ctx, B_5_0, REQ_SEM_OBTAIN_RELEASE);
+  send_event(ctx, H_A, REQ_SEM_RELEASE);
+  check_generations(ctx, NONE, NONE);
+
+  /*
+   * We are in scheduler instance A.  Task B_5_0 of scheduler instance B issued
+   * the counting semaphore obtain before us.  However, we inherited the
+   * priority of B_4, so we get the semaphore before B_5_0 (priority order
+   * within scheduler instance B).
+   */
+  sem_obtain(ctx);
+  check_generations(ctx, NONE, NONE);
+
+  release(ctx);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+  sync_with_helper(ctx);
+  check_generations(ctx, B_4, NONE);
+
+  request(ctx, B_4, REQ_MTX_RELEASE);
+  check_generations(ctx, B_4, NONE);
+
+  sem_release(ctx);
+  sync_with_helper(ctx);
+  check_generations(ctx, B_5_0, NONE);
+
+  sem_obtain(ctx);
+}
+
+static void test_mixed_queue_two_scheduler_instances_sem_only(test_context *ctx)
+{
+  request(ctx, B_5_0, REQ_SEM_OBTAIN_RELEASE);
+  send_event(ctx, H_A, REQ_SEM_RELEASE);
+  check_generations(ctx, NONE, NONE);
+
+  /*
+   * We are in scheduler instance A.  Task B_5_0 of scheduler instance B issued
+   * the counting semaphore obtain before us.  No priority inheritance is
+   * involved, so task B_5_0 gets the counting semaphore first.
+   */
+  sem_obtain(ctx);
+  check_generations(ctx, B_5_0, NONE);
+
+  sem_release(ctx);
+}
+
+static void test_simple_inheritance_two_scheduler_instances(test_context *ctx)
 {
   obtain(ctx);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+
   request(ctx, B_5_0, REQ_MTX_OBTAIN);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, 5);
+
   request(ctx, B_4, REQ_MTX_OBTAIN);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
+
   request(ctx, B_5_1, REQ_MTX_OBTAIN);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
   check_generations(ctx, NONE, NONE);
-  assert_prio(ctx, M, 0);
+
   release(ctx);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
   sync_with_helper(ctx);
-  assert_prio(ctx, M, 3);
   check_generations(ctx, B_4, NONE);
+
   request(ctx, B_4, REQ_MTX_RELEASE);
   check_generations(ctx, B_4, B_5_0);
+
   request(ctx, B_5_0, REQ_MTX_RELEASE);
   check_generations(ctx, B_5_0, B_5_1);
+
   request(ctx, B_5_1, REQ_MTX_RELEASE);
   check_generations(ctx, B_5_1, NONE);
 }
 
+static void test_nested_inheritance_two_scheduler_instances(test_context *ctx)
+{
+  obtain_2(ctx);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+
+  request(ctx, B_5_0, REQ_MTX_OBTAIN);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
+  check_generations(ctx, B_5_0, NONE);
+
+  request(ctx, B_5_0, REQ_MTX_2_OBTAIN);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, 5);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
+
+  request(ctx, B_4, REQ_MTX_OBTAIN_TIMEOUT);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 4);
+  wait();
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, 5);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
+  check_generations(ctx, B_4, NONE);
+
+  request(ctx, B_4, REQ_MTX_OBTAIN);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 4);
+
+  request(ctx, B_5_1, REQ_MTX_2_OBTAIN);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 4);
+  check_generations(ctx, NONE, NONE);
+
+  release_2(ctx);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 4);
+  sync_with_helper(ctx);
+  check_generations(ctx, B_5_0, NONE);
+
+  request(ctx, B_5_0, REQ_MTX_RELEASE);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
+  check_generations(ctx, B_4, B_5_0);
+
+  request(ctx, B_4, REQ_MTX_RELEASE);
+  check_generations(ctx, B_4, NONE);
+
+  request(ctx, B_5_0, REQ_MTX_2_RELEASE);
+  check_generations(ctx, B_5_0, B_5_1);
+
+  request(ctx, B_5_1, REQ_MTX_2_RELEASE);
+  check_generations(ctx, B_5_1, NONE);
+}
+
 static void test_dequeue_order_two_scheduler_instances(test_context *ctx)
 {
   obtain(ctx);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+
   request(ctx, A_2_0, REQ_MTX_OBTAIN);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 2);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
   check_generations(ctx, NONE, NONE);
-  assert_prio(ctx, M, 2);
+
   request(ctx, B_5_0, REQ_MTX_OBTAIN);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 2);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, 5);
   check_generations(ctx, NONE, NONE);
-  assert_prio(ctx, M, 0);
+
   request(ctx, B_5_1, REQ_MTX_OBTAIN);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 2);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, 5);
+
   request(ctx, B_4, REQ_MTX_OBTAIN);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 2);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
+
   request(ctx, A_2_1, REQ_MTX_OBTAIN);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 2);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
+
   request(ctx, A_1, REQ_MTX_OBTAIN);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 1);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
   check_generations(ctx, NONE, NONE);
+
   release(ctx);
   sync_with_helper(ctx);
+  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
+  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, A_1, SCHED_A, 1);
+  assert_prio_by_scheduler(ctx, A_1, SCHED_B, 4);
   check_generations(ctx, A_1, NONE);
-  assert_prio(ctx, M, 3);
-  assert_prio(ctx, A_1, 0);
+
   request(ctx, A_1, REQ_MTX_RELEASE);
+  assert_prio_by_scheduler(ctx, A_1, SCHED_A, 1);
+  assert_prio_by_scheduler(ctx, A_1, SCHED_B, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, B_4, SCHED_A, 2);
+  assert_prio_by_scheduler(ctx, B_4, SCHED_B, 4);
   check_generations(ctx, A_1, B_4);
-  assert_prio(ctx, A_1, 1);
-  assert_prio(ctx, B_4, 0);
+
   request(ctx, B_4, REQ_MTX_RELEASE);
+  assert_prio_by_scheduler(ctx, B_4, SCHED_A, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, B_4, SCHED_B, 4);
+  assert_prio_by_scheduler(ctx, A_2_0, SCHED_A, 2);
+  assert_prio_by_scheduler(ctx, A_2_0, SCHED_B, 5);
   check_generations(ctx, B_4, A_2_0);
-  assert_prio(ctx, B_4, 4);
-  assert_prio(ctx, A_2_0, 0);
+
   request(ctx, A_2_0, REQ_MTX_RELEASE);
+  assert_prio_by_scheduler(ctx, A_2_0, SCHED_A, 2);
+  assert_prio_by_scheduler(ctx, A_2_0, SCHED_B, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, 2);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
   check_generations(ctx, A_2_0, B_5_0);
-  assert_prio(ctx, A_2_0, 2);
-  assert_prio(ctx, B_5_0, 0);
+
   request(ctx, B_5_0, REQ_MTX_RELEASE);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
+  assert_prio_by_scheduler(ctx, A_2_1, SCHED_A, 2);
+  assert_prio_by_scheduler(ctx, A_2_1, SCHED_B, 5);
   check_generations(ctx, B_5_0, A_2_1);
-  assert_prio(ctx, B_5_0, 5);
-  assert_prio(ctx, A_2_1, 2);
+
   request(ctx, A_2_1, REQ_MTX_RELEASE);
+  assert_prio_by_scheduler(ctx, A_2_1, SCHED_A, 2);
+  assert_prio_by_scheduler(ctx, A_2_1, SCHED_B, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, B_5_1, SCHED_A, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, B_5_1, SCHED_B, 5);
   check_generations(ctx, A_2_1, B_5_1);
-  assert_prio(ctx, B_5_1, 5);
+
   request(ctx, B_5_1, REQ_MTX_RELEASE);
+  assert_prio_by_scheduler(ctx, B_5_1, SCHED_A, PRIO_NONE);
+  assert_prio_by_scheduler(ctx, B_5_1, SCHED_B, 5);
   check_generations(ctx, B_5_1, NONE);
-  assert_prio(ctx, B_5_1, 5);
 }
 
 static void test(void)
@@ -358,7 +680,10 @@ static void test(void)
   test_task_get_priority_not_defined(ctx);
   test_simple_inheritance(ctx);
   test_dequeue_order_one_scheduler_instance(ctx);
-  test_simple_boosting(ctx);
+  test_mixed_queue_two_scheduler_instances(ctx);
+  test_mixed_queue_two_scheduler_instances_sem_only(ctx);
+  test_simple_inheritance_two_scheduler_instances(ctx);
+  test_nested_inheritance_two_scheduler_instances(ctx);
   test_dequeue_order_two_scheduler_instances(ctx);
 }
 
@@ -399,7 +724,7 @@ RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(b);
 
 #define CONFIGURE_MAXIMUM_TASKS TASK_COUNT
 
-#define CONFIGURE_MAXIMUM_SEMAPHORES 1
+#define CONFIGURE_MAXIMUM_SEMAPHORES 3
 
 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
 



More information about the vc mailing list