[rtems commit] score: Add thread priority change handler

Sebastian Huber sebh at rtems.org
Tue Mar 24 13:36:29 UTC 2015


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

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Tue Mar 17 16:28:50 2015 +0100

score: Add thread priority change handler

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 ++++++++++----------------
 testsuites/sptests/spintrcritical23/init.c     |  4 +-
 7 files changed, 133 insertions(+), 71 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 );
-  }
-}
diff --git a/testsuites/sptests/spintrcritical23/init.c b/testsuites/sptests/spintrcritical23/init.c
index 89fea25..8536489 100644
--- a/testsuites/sptests/spintrcritical23/init.c
+++ b/testsuites/sptests/spintrcritical23/init.c
@@ -70,7 +70,7 @@ static void change_priority(rtems_id timer, void *arg)
 
   rtems_interrupt_lock_acquire(&ctx->lock, &lock_context);
   if (
-    ctx->priority_generation != ctx->tcb->priority_generation
+    ctx->priority_generation != ctx->tcb->Priority.generation
       && scheduler_node_unchanged(ctx)
   ) {
     rtems_task_priority priority_interrupt;
@@ -113,7 +113,7 @@ static bool test_body(void *arg)
   priority_interrupt = 1 + (priority_task + 1) % 3;
   ctx->priority_task = priority_task;
   ctx->priority_interrupt = priority_interrupt;
-  ctx->priority_generation = ctx->tcb->priority_generation;
+  ctx->priority_generation = ctx->tcb->Priority.generation;
   memcpy(
     &ctx->scheduler_node,
     ctx->tcb->Scheduler.node,



More information about the vc mailing list