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 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel