summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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,