[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