[PATCH v2 3/5] score: Priority inherit thread queue operations

Sebastian Huber sebastian.huber at embedded-brains.de
Tue Jul 26 09:20:50 UTC 2016


Move the priority change due to priority interitance to the thread queue
enqueue operation to simplify the locking on SMP configurations.

Update #2412.
Update #2556.
Update #2765.
---
 cpukit/score/include/rtems/score/coremuteximpl.h |  3 +
 cpukit/score/include/rtems/score/threadimpl.h    | 31 ----------
 cpukit/score/include/rtems/score/threadq.h       |  9 ++-
 cpukit/score/include/rtems/score/threadqimpl.h   | 23 +++++++
 cpukit/score/src/coremutexseize.c                |  4 +-
 cpukit/score/src/mutex.c                         |  3 +-
 cpukit/score/src/threadchangepriority.c          | 34 -----------
 cpukit/score/src/threadqenqueue.c                |  8 ++-
 cpukit/score/src/threadqops.c                    | 78 +++++++++++++++++++++++-
 9 files changed, 116 insertions(+), 77 deletions(-)

diff --git a/cpukit/score/include/rtems/score/coremuteximpl.h b/cpukit/score/include/rtems/score/coremuteximpl.h
index 339834b..f48524a 100644
--- a/cpukit/score/include/rtems/score/coremuteximpl.h
+++ b/cpukit/score/include/rtems/score/coremuteximpl.h
@@ -36,6 +36,9 @@ extern "C" {
 
 #define CORE_MUTEX_TQ_OPERATIONS &_Thread_queue_Operations_priority
 
+#define CORE_MUTEX_TQ_PRIORITY_INHERIT_OPERATIONS \
+  &_Thread_queue_Operations_priority_inherit
+
 RTEMS_INLINE_ROUTINE void _CORE_mutex_Initialize(
   CORE_mutex_Control *the_mutex
 )
diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h
index 5323e2c..92968a2 100644
--- a/cpukit/score/include/rtems/score/threadimpl.h
+++ b/cpukit/score/include/rtems/score/threadimpl.h
@@ -512,37 +512,6 @@ void _Thread_Raise_priority(
 );
 
 /**
- * @brief Inherit the priority of a thread.
- *
- * It changes the current priority of the inheritor thread to the current priority
- * of the ancestor thread if it is higher than the current priority of the inheritor
- * thread.  In this case the inheritor thread is appended to its new priority group
- * in its scheduler instance.
- *
- * On SMP configurations, the priority is changed to PRIORITY_PSEUDO_ISR in
- * case the own schedulers of the inheritor and ancestor thread differ (priority
- * boosting).
- *
- * @param[in] inheritor The thread to inherit the priority.
- * @param[in] ancestor The thread to bequeath its priority to the inheritor
- *   thread.
- */
-#if defined(RTEMS_SMP)
-void _Thread_Inherit_priority(
-  Thread_Control *inheritor,
-  Thread_Control *ancestor
-);
-#else
-RTEMS_INLINE_ROUTINE void _Thread_Inherit_priority(
-  Thread_Control *inheritor,
-  Thread_Control *ancestor
-)
-{
-  _Thread_Raise_priority( inheritor, ancestor->current_priority );
-}
-#endif
-
-/**
  * @brief Sets the current to the real priority of a thread.
  *
  * Sets the priority restore hint to false.
diff --git a/cpukit/score/include/rtems/score/threadq.h b/cpukit/score/include/rtems/score/threadq.h
index b3b8fec..75aab20 100644
--- a/cpukit/score/include/rtems/score/threadq.h
+++ b/cpukit/score/include/rtems/score/threadq.h
@@ -43,6 +43,8 @@ extern "C" {
 
 typedef struct _Thread_Control Thread_Control;
 
+typedef struct Thread_queue_Path Thread_queue_Path;
+
 #if defined(RTEMS_MULTIPROCESSING)
 /**
  * @brief Multiprocessing (MP) support callout for thread queue operations.
@@ -239,6 +241,10 @@ typedef void ( *Thread_queue_Priority_change_operation )(
 /**
  * @brief Thread queue enqueue operation.
  *
+ * A potential thread to update the priority due to priority inheritance is
+ * returned via the thread queue path.  This thread is handed over to
+ * _Thread_Update_priority().
+ *
  * @param[in] queue The actual thread queue.
  * @param[in] the_thread The thread to enqueue on the queue.
  *
@@ -246,7 +252,8 @@ typedef void ( *Thread_queue_Priority_change_operation )(
  */
 typedef void ( *Thread_queue_Enqueue_operation )(
   Thread_queue_Queue *queue,
-  Thread_Control     *the_thread
+  Thread_Control     *the_thread,
+  Thread_queue_Path  *path
 );
 
 /**
diff --git a/cpukit/score/include/rtems/score/threadqimpl.h b/cpukit/score/include/rtems/score/threadqimpl.h
index 2d396cb..1502b09 100644
--- a/cpukit/score/include/rtems/score/threadqimpl.h
+++ b/cpukit/score/include/rtems/score/threadqimpl.h
@@ -36,6 +36,27 @@ extern "C" {
 /**@{*/
 
 /**
+ * @brief Representation of a thread queue path from a start thread queue to
+ * the terminal thread queue.
+ *
+ * The start thread queue is determined by the object on which a thread intends
+ * to block.  The terminal thread queue is the thread queue reachable via
+ * thread queue links those owner is not blocked on a thread queue.  The thread
+ * queue links are determined by the thread queue owner and thread wait queue
+ * relationships.
+ */
+struct Thread_queue_Path {
+  /**
+   * @brief A potential thread to update the priority via
+   * _Thread_Update_priority().
+   *
+   * This thread is determined by thread queues which support priority
+   * inheritance.
+   */
+  Thread_Control *update_priority;
+};
+
+/**
  * @brief Thread queue with a layout compatible to struct _Thread_queue_Queue
  * defined in Newlib <sys/lock.h>.
  */
@@ -888,6 +909,8 @@ extern const Thread_queue_Operations _Thread_queue_Operations_FIFO;
 
 extern const Thread_queue_Operations _Thread_queue_Operations_priority;
 
+extern const Thread_queue_Operations _Thread_queue_Operations_priority_inherit;
+
 /**@}*/
 
 #ifdef __cplusplus
diff --git a/cpukit/score/src/coremutexseize.c b/cpukit/score/src/coremutexseize.c
index c468c07..dacb274 100644
--- a/cpukit/score/src/coremutexseize.c
+++ b/cpukit/score/src/coremutexseize.c
@@ -54,8 +54,6 @@ Status_Control _CORE_mutex_Seize_slow(
   _CORE_mutex_Release( the_mutex, queue_context );
 #endif
 
-  _Thread_Inherit_priority( owner, executing );
-
 #if defined(RTEMS_SMP)
   _Thread_queue_Context_set_expected_level( queue_context, 1 );
 #else
@@ -66,7 +64,7 @@ Status_Control _CORE_mutex_Seize_slow(
 
   _Thread_queue_Enqueue_critical(
     &the_mutex->Wait_queue.Queue,
-    CORE_MUTEX_TQ_OPERATIONS,
+    CORE_MUTEX_TQ_PRIORITY_INHERIT_OPERATIONS,
     executing,
     STATES_WAITING_FOR_MUTEX,
     queue_context
diff --git a/cpukit/score/src/mutex.c b/cpukit/score/src/mutex.c
index 4b95262..12a4f29 100644
--- a/cpukit/score/src/mutex.c
+++ b/cpukit/score/src/mutex.c
@@ -26,7 +26,7 @@
 #include <rtems/score/threadqimpl.h>
 #include <rtems/score/todimpl.h>
 
-#define MUTEX_TQ_OPERATIONS &_Thread_queue_Operations_priority
+#define MUTEX_TQ_OPERATIONS &_Thread_queue_Operations_priority_inherit
 
 typedef struct {
   Thread_queue_Syslock_queue Queue;
@@ -107,7 +107,6 @@ static void _Mutex_Acquire_slow(
   Thread_queue_Context *queue_context
 )
 {
-  _Thread_Inherit_priority( owner, executing );
   _Thread_queue_Context_set_expected_level( queue_context, 1 );
   _Thread_queue_Enqueue_critical(
     &mutex->Queue.Queue,
diff --git a/cpukit/score/src/threadchangepriority.c b/cpukit/score/src/threadchangepriority.c
index d895ee6..e3cf4a1 100644
--- a/cpukit/score/src/threadchangepriority.c
+++ b/cpukit/score/src/threadchangepriority.c
@@ -142,40 +142,6 @@ void _Thread_Raise_priority(
   );
 }
 
-#if defined(RTEMS_SMP)
-static bool _Thread_Inherit_priority_filter(
-  Thread_Control   *inheritor,
-  Priority_Control *new_priority,
-  void             *arg
-)
-{
-  Thread_Control *ancestor = arg;
-
-  if ( _Scheduler_Get_own( inheritor ) == _Scheduler_Get_own( ancestor ) ) {
-    *new_priority = ancestor->current_priority;
-  }
-
-  return _Thread_Priority_less_than(
-    inheritor->current_priority,
-    *new_priority
-  );
-}
-
-void _Thread_Inherit_priority(
-  Thread_Control *inheritor,
-  Thread_Control *ancestor
-)
-{
-  _Thread_Change_priority(
-    inheritor,
-    PRIORITY_PSEUDO_ISR,
-    ancestor,
-    _Thread_Inherit_priority_filter,
-    false
-  );
-}
-#endif
-
 static bool _Thread_Restore_priority_filter(
   Thread_Control   *the_thread,
   Priority_Control *new_priority,
diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c
index 1528b48..818073c 100644
--- a/cpukit/score/src/threadqenqueue.c
+++ b/cpukit/score/src/threadqenqueue.c
@@ -42,8 +42,9 @@ void _Thread_queue_Enqueue_critical(
   Thread_queue_Context          *queue_context
 )
 {
-  Per_CPU_Control *cpu_self;
-  bool             success;
+  Thread_queue_Path  path;
+  Per_CPU_Control   *cpu_self;
+  bool               success;
 
 #if defined(RTEMS_MULTIPROCESSING)
   if ( _Thread_MP_Is_receive( the_thread ) && the_thread->receive_packet ) {
@@ -57,7 +58,7 @@ void _Thread_queue_Enqueue_critical(
   _Thread_Wait_set_queue( the_thread, queue );
   _Thread_Wait_set_operations( the_thread, operations );
 
-  ( *operations->enqueue )( queue, the_thread );
+  ( *operations->enqueue )( queue, the_thread, &path );
 
   _Thread_Wait_flags_set( the_thread, THREAD_QUEUE_INTEND_TO_BLOCK );
   cpu_self = _Thread_Dispatch_disable_critical( &queue_context->Lock_context );
@@ -124,6 +125,7 @@ void _Thread_queue_Enqueue_critical(
     _Thread_Remove_timer_and_unblock( the_thread, queue );
   }
 
+  _Thread_Update_priority( path.update_priority );
   _Thread_Dispatch_enable( cpu_self );
 }
 
diff --git a/cpukit/score/src/threadqops.c b/cpukit/score/src/threadqops.c
index 83abf0d..c288cee 100644
--- a/cpukit/score/src/threadqops.c
+++ b/cpukit/score/src/threadqops.c
@@ -39,7 +39,7 @@ static void _Thread_queue_Do_nothing_extract(
   /* Do nothing */
 }
 
-static void _Thread_queue_Queue_enqueue(
+static Thread_queue_Heads *_Thread_queue_Queue_enqueue(
   Thread_queue_Queue *queue,
   Thread_Control     *the_thread,
   void             ( *initialize )( Thread_queue_Heads * ),
@@ -62,6 +62,8 @@ static void _Thread_queue_Queue_enqueue(
   _Chain_Prepend_unprotected( &heads->Free_chain, &spare_heads->Free_node );
 
   ( *enqueue )( heads, the_thread );
+
+  return heads;
 }
 
 static void _Thread_queue_Queue_extract(
@@ -116,9 +118,12 @@ static void _Thread_queue_FIFO_do_extract(
 
 static void _Thread_queue_FIFO_enqueue(
   Thread_queue_Queue *queue,
-  Thread_Control     *the_thread
+  Thread_Control     *the_thread,
+  Thread_queue_Path  *path
 )
 {
+  path->update_priority = NULL;
+
   _Thread_queue_Queue_enqueue(
     queue,
     the_thread,
@@ -266,9 +271,12 @@ static void _Thread_queue_Priority_do_extract(
 
 static void _Thread_queue_Priority_enqueue(
   Thread_queue_Queue *queue,
-  Thread_Control     *the_thread
+  Thread_Control     *the_thread,
+  Thread_queue_Path  *path
 )
 {
+  path->update_priority = NULL;
+
   _Thread_queue_Queue_enqueue(
     queue,
     the_thread,
@@ -310,6 +318,63 @@ static Thread_Control *_Thread_queue_Priority_first(
   return THREAD_RBTREE_NODE_TO_THREAD( first );
 }
 
+static void _Thread_queue_Priority_inherit_enqueue(
+  Thread_queue_Queue *queue,
+  Thread_Control     *the_thread,
+  Thread_queue_Path  *path
+)
+{
+  Thread_queue_Heads *heads;
+  Thread_Control     *owner;
+  Priority_Control    priority;
+
+  heads = _Thread_queue_Queue_enqueue(
+    queue,
+    the_thread,
+    _Thread_queue_Priority_do_initialize,
+    _Thread_queue_Priority_do_enqueue
+  );
+
+  owner = queue->owner;
+
+#if defined(RTEMS_SMP)
+  if ( _Chain_Has_only_one_node( &heads->Heads.Fifo ) ) {
+    priority = the_thread->current_priority;
+  } else {
+    priority = _Scheduler_Map_priority(
+      _Scheduler_Get_own( the_thread ),
+      PRIORITY_PSEUDO_ISR
+    );
+  }
+#else
+  (void) heads;
+
+  priority = the_thread->current_priority;
+#endif
+
+  if ( priority < owner->current_priority ) {
+    Scheduler_Node *own_node;
+
+    path->update_priority = owner;
+
+    owner->priority_restore_hint = true;
+    _Atomic_Fence( ATOMIC_ORDER_ACQ_REL );
+
+    own_node = _Scheduler_Thread_get_own_node( owner );
+    _Scheduler_Node_set_priority( own_node, priority, false );
+
+    owner->current_priority = priority;
+
+    ( *owner->Wait.operations->priority_change )(
+      owner,
+      priority,
+      owner->Wait.queue
+    );
+  } else {
+    path->update_priority = NULL;
+  }
+}
+
 #if defined(RTEMS_SMP)
 void _Thread_queue_Boost_priority(
   Thread_queue_Queue *queue,
@@ -359,3 +424,10 @@ const Thread_queue_Operations _Thread_queue_Operations_priority = {
   .extract = _Thread_queue_Priority_extract,
   .first = _Thread_queue_Priority_first
 };
+
+const Thread_queue_Operations _Thread_queue_Operations_priority_inherit = {
+  .priority_change = _Thread_queue_Priority_priority_change,
+  .enqueue = _Thread_queue_Priority_inherit_enqueue,
+  .extract = _Thread_queue_Priority_extract,
+  .first = _Thread_queue_Priority_first
+};
-- 
1.8.4.5




More information about the devel mailing list