summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2015-03-17 16:28:50 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2015-03-24 14:35:04 +0100
commit2e9c3d5e2944a8782eac8a12d23af7559873ad0a (patch)
treed19a9f00f4ca76811e3e4d25af5b48f50a2d47c1
parentcpukit/libmisc/utf8proc/utf8proc.c: Avoid overflow (diff)
downloadrtems-2e9c3d5e2944a8782eac8a12d23af7559873ad0a.tar.bz2
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.
-rw-r--r--cpukit/score/include/rtems/score/thread.h57
-rw-r--r--cpukit/score/include/rtems/score/threadimpl.h35
-rw-r--r--cpukit/score/include/rtems/score/threadqimpl.h17
-rw-r--r--cpukit/score/src/threadchangepriority.c12
-rw-r--r--cpukit/score/src/threadinitialize.c12
-rw-r--r--cpukit/score/src/threadqenqueue.c67
-rw-r--r--testsuites/sptests/spintrcritical23/init.c4
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 11f60f324b..ee7886c934 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 b968a055c9..5376ce1660 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 4a1084dde5..4c8d22edae 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 6ee65f53cc..dea671de3f 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 993d95fdb8..b0066cd19a 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 39353fe6d4..572d8403ff 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 89fea25a12..8536489f5d 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,