[PATCH 1/3] score: Add thread priority change handler

Sebastian Huber sebastian.huber at embedded-brains.de
Mon Mar 23 14:51:45 UTC 2015


Since the thread current priority change and thread queue requeue is
performed in one critical section it is possible to simplify the thread
queue requeue procedure.  Add a thread queue agnostic thread priority
change handler so that we are able to use alternative thread queue
implementations.

Update #2273.
---
 cpukit/score/include/rtems/score/thread.h      | 57 ++++++++++++++++++++--
 cpukit/score/include/rtems/score/threadimpl.h  | 35 ++++++++++++++
 cpukit/score/include/rtems/score/threadqimpl.h | 17 -------
 cpukit/score/src/threadchangepriority.c        | 12 +++--
 cpukit/score/src/threadinitialize.c            | 12 ++++-
 cpukit/score/src/threadqenqueue.c              | 67 ++++++++++----------------
 6 files changed, 131 insertions(+), 69 deletions(-)

diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h
index 11f60f3..ee7886c 100644
--- a/cpukit/score/include/rtems/score/thread.h
+++ b/cpukit/score/include/rtems/score/thread.h
@@ -374,6 +374,56 @@ typedef enum {
 /** This macro defines the last API which has threads. */
 #define THREAD_API_LAST  THREAD_API_POSIX
 
+/**
+ * @brief Priority change handler.
+ *
+ * @param[in] the_thread The thread.
+ * @param[in] new_priority The new priority value.
+ * @param[in] context The handler context.
+ *
+ * @see _Thread_Priority_set_change_handler().
+ */
+typedef void (*Thread_Priority_change_handler)(
+  Thread_Control   *the_thread,
+  Priority_Control  new_priority,
+  void             *context
+);
+
+/**
+ * @brief Thread priority control.
+ */
+typedef struct {
+  /**
+   * @brief Generation of the current priority value.
+   *
+   * It is used in _Thread_Change_priority() to serialize the update of
+   * priority related data structures.
+   */
+  uint32_t generation;
+
+  /**
+   * @brief Priority change handler.
+   *
+   * Called by _Thread_Change_priority() to notify a thread about a priority
+   * change.  In case this thread waits currently for a resource the handler
+   * may adjust its data structures according to the new priority value.  This
+   * handler must not be NULL, instead the default handler
+   * _Thread_Priority_change_do_nothing() should be used in case nothing needs
+   * to be done during a priority change.
+   *
+   * @see _Thread_Priority_set_change_handler() and
+   * _Thread_Priority_restore_default_change_handler().
+   */
+  Thread_Priority_change_handler change_handler;
+
+  /**
+   * @brief Context for priority change handler.
+   *
+   * @see _Thread_Priority_set_change_handler().
+   */
+  void *change_handler_context;
+} Thread_Priority_control;
+
 typedef struct Thread_Action Thread_Action;
 
 /**
@@ -584,12 +634,9 @@ struct Thread_Control_struct {
   Priority_Control         real_priority;
 
   /**
-   * @brief Generation of the current priority value.
-   *
-   * It is used in _Thread_Change_priority() to serialize the update of
-   * priority related data structures.
+   * @brief Thread priority control.
    */
-  uint32_t                 priority_generation;
+  Thread_Priority_control  Priority;
 
   /** This field is the number of mutexes currently held by this thread. */
   uint32_t                 resource_count;
diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h
index b968a05..5376ce1 100644
--- a/cpukit/score/include/rtems/score/threadimpl.h
+++ b/cpukit/score/include/rtems/score/threadimpl.h
@@ -883,6 +883,41 @@ RTEMS_INLINE_ROUTINE bool _Thread_Owns_resources(
   return owns_resources;
 }
 
+void _Thread_Priority_change_do_nothing(
+  Thread_Control   *the_thread,
+  Priority_Control  new_priority,
+  void             *context
+);
+
+/**
+ * @brief Sets the thread priority change handler and its context.
+ *
+ * @param[in] the_thread The thread.
+ * @param[in] new_handler The new handler.
+ * @param[in] new_context The new handler context.
+ */
+RTEMS_INLINE_ROUTINE void _Thread_Priority_set_change_handler(
+  Thread_Control                 *the_thread,
+  Thread_Priority_change_handler  new_handler,
+  void                           *new_context
+)
+{
+  the_thread->Priority.change_handler = new_handler;
+  the_thread->Priority.change_handler_context = new_context;
+}
+
+/**
+ * @brief Restores the thread priority change default handler and its context.
+ *
+ * @param[in] the_thread The thread.
+ */
+RTEMS_INLINE_ROUTINE void _Thread_Priority_restore_default_change_handler(
+  Thread_Control *the_thread
+)
+{
+  the_thread->Priority.change_handler = _Thread_Priority_change_do_nothing;
+}
+
 /**
  * @brief The initial thread wait flags value set by _Thread_Initialize().
  */
diff --git a/cpukit/score/include/rtems/score/threadqimpl.h b/cpukit/score/include/rtems/score/threadqimpl.h
index 4a1084d..4c8d22e 100644
--- a/cpukit/score/include/rtems/score/threadqimpl.h
+++ b/cpukit/score/include/rtems/score/threadqimpl.h
@@ -266,23 +266,6 @@ RBTree_Compare_result _Thread_queue_Compare_priority(
 );
 
 /**
- *  @brief Invoked when a thread changes priority and is blocked.
- *
- *  This routine is invoked when a thread changes priority and is
- *  blocked on a thread queue.  If the queue is priority ordered,
- *  the_thread is removed from the_thread_queue and reinserted using
- *  its new priority.  This method has no impact on the state of the_thread
- *  or of any timeouts associated with this blocking.
- *
- *  @param[in] the_thread_queue pointer to a threadq header
- *  @param[in] the_thread pointer to a thread control block
- */
-void _Thread_queue_Requeue(
-  Thread_queue_Control *the_thread_queue,
-  Thread_Control       *the_thread
-);
-
-/**
  * This routine is invoked to indicate that the specified thread queue is
  * entering a critical section.
  */
diff --git a/cpukit/score/src/threadchangepriority.c b/cpukit/score/src/threadchangepriority.c
index 6ee65f5..dea671d 100644
--- a/cpukit/score/src/threadchangepriority.c
+++ b/cpukit/score/src/threadchangepriority.c
@@ -38,16 +38,20 @@ void _Thread_Change_priority(
    *  we are not REALLY changing priority.
    */
   if ( the_thread->current_priority != new_priority ) {
-    uint32_t my_generation = the_thread->priority_generation + 1;
+    uint32_t my_generation = the_thread->Priority.generation + 1;
 
     the_thread->current_priority = new_priority;
-    the_thread->priority_generation = my_generation;
+    the_thread->Priority.generation = my_generation;
 
-    _Thread_queue_Requeue( the_thread->Wait.queue, the_thread );
+    (*the_thread->Priority.change_handler)(
+      the_thread,
+      new_priority,
+      the_thread->Priority.change_handler_context
+    );
 
     _ISR_Flash( level );
 
-    if ( the_thread->priority_generation == my_generation ) {
+    if ( the_thread->Priority.generation == my_generation ) {
       if ( _States_Is_ready( the_thread->current_state ) ) {
         _Scheduler_Change_priority(
           the_thread,
diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c
index 993d95f..b0066cd 100644
--- a/cpukit/score/src/threadinitialize.c
+++ b/cpukit/score/src/threadinitialize.c
@@ -29,6 +29,15 @@
 #include <rtems/score/cpusetimpl.h>
 #include <rtems/config.h>
 
+void _Thread_Priority_change_do_nothing(
+  Thread_Control   *the_thread,
+  Priority_Control  new_priority,
+  void             *context
+)
+{
+  /* Do nothing */
+}
+
 bool _Thread_Initialize(
   Objects_Information                  *information,
   Thread_Control                       *the_thread,
@@ -198,7 +207,8 @@ bool _Thread_Initialize(
   the_thread->Wait.queue              = NULL;
   the_thread->resource_count          = 0;
   the_thread->real_priority           = priority;
-  the_thread->priority_generation     = 0;
+  the_thread->Priority.generation     = 0;
+  the_thread->Priority.change_handler = _Thread_Priority_change_do_nothing;
   the_thread->Start.initial_priority  = priority;
 
   _Thread_Wait_flags_set( the_thread, THREAD_WAIT_FLAGS_INITIAL );
diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c
index 39353fe..572d840 100644
--- a/cpukit/score/src/threadqenqueue.c
+++ b/cpukit/score/src/threadqenqueue.c
@@ -73,6 +73,24 @@ static void _Thread_blocking_operation_Finalize(
 #endif
 }
 
+static void _Thread_queue_Requeue_priority(
+  Thread_Control   *the_thread,
+  Priority_Control  new_priority,
+  void             *context
+)
+{
+  Thread_queue_Control *tq = context;
+
+  _Thread_queue_Enter_critical_section( tq );
+  _RBTree_Extract( &tq->Queues.Priority, &the_thread->RBNode );
+  _RBTree_Insert(
+    &tq->Queues.Priority,
+    &the_thread->RBNode,
+    _Thread_queue_Compare_priority,
+    false
+  );
+}
+
 void _Thread_queue_Enqueue_with_handler(
   Thread_queue_Control         *the_thread_queue,
   Thread_Control               *the_thread,
@@ -127,6 +145,11 @@ void _Thread_queue_Enqueue_with_handler(
         &the_thread->Object.Node
       );
     } else { /* must be THREAD_QUEUE_DISCIPLINE_PRIORITY */
+      _Thread_Priority_set_change_handler(
+        the_thread,
+        _Thread_queue_Requeue_priority,
+        the_thread_queue
+      );
       _RBTree_Insert(
         &the_thread_queue->Queues.Priority,
         &the_thread->RBNode,
@@ -172,6 +195,7 @@ void _Thread_queue_Extract_with_return_code(
       &the_thread->Wait.queue->Queues.Priority,
       &the_thread->RBNode
     );
+    _Thread_Priority_restore_default_change_handler( the_thread );
   }
 
   the_thread->Wait.return_code = return_code;
@@ -221,6 +245,7 @@ Thread_Control *_Thread_queue_Dequeue(
     first = _RBTree_Get( &the_thread_queue->Queues.Priority, RBT_LEFT );
     if ( first ) {
       the_thread = THREAD_RBTREE_NODE_TO_THREAD( first );
+      _Thread_Priority_restore_default_change_handler( the_thread );
     }
   }
 
@@ -249,45 +274,3 @@ Thread_Control *_Thread_queue_Dequeue(
 
   return the_thread;
 }
-
-void _Thread_queue_Requeue(
-  Thread_queue_Control *the_thread_queue,
-  Thread_Control       *the_thread
-)
-{
-  /*
-   * Just in case the thread really wasn't blocked on a thread queue
-   * when we get here.
-   */
-  if ( !the_thread_queue )
-    return;
-
-  /*
-   * If queueing by FIFO, there is nothing to do. This only applies to
-   * priority blocking discipline.
-   */
-  if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_PRIORITY ) {
-    Thread_queue_Control *tq = the_thread_queue;
-    ISR_Level             level;
-
-    _ISR_Disable( level );
-    if ( _States_Is_waiting_on_thread_queue( the_thread->current_state ) ) {
-      _Thread_queue_Enter_critical_section( tq );
-
-      /* extract the thread */
-      _RBTree_Extract(
-        &the_thread->Wait.queue->Queues.Priority,
-        &the_thread->RBNode
-      );
-
-      /* enqueue the thread at the new priority */
-      _RBTree_Insert(
-        &the_thread_queue->Queues.Priority,
-        &the_thread->RBNode,
-        _Thread_queue_Compare_priority,
-        false
-      );
-    }
-    _ISR_Enable( level );
-  }
-}
-- 
1.8.4.5



More information about the devel mailing list