diff options
Diffstat (limited to 'cpukit/score/src/threadchangepriority.c')
-rw-r--r-- | cpukit/score/src/threadchangepriority.c | 217 |
1 files changed, 189 insertions, 28 deletions
diff --git a/cpukit/score/src/threadchangepriority.c b/cpukit/score/src/threadchangepriority.c index 13e9147916..78291b7798 100644 --- a/cpukit/score/src/threadchangepriority.c +++ b/cpukit/score/src/threadchangepriority.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * @@ -14,11 +16,28 @@ * COPYRIGHT (c) 1989-2014. * On-Line Applications Research Corporation (OAR). * - * Copyright (c) 2013, 2016 embedded brains GmbH + * Copyright (C) 2013, 2016 embedded brains GmbH & Co. KG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H @@ -31,13 +50,13 @@ static void _Thread_Set_scheduler_node_priority( Priority_Aggregation *priority_aggregation, - bool prepend_it + Priority_Group_order priority_group_order ) { _Scheduler_Node_set_priority( SCHEDULER_NODE_OF_WAIT_PRIORITY_NODE( priority_aggregation ), _Priority_Get_priority( priority_aggregation ), - prepend_it + priority_group_order ); } @@ -55,7 +74,10 @@ static void _Thread_Priority_action_add( the_thread = arg; _Thread_Scheduler_add_wait_node( the_thread, scheduler_node ); - _Thread_Set_scheduler_node_priority( priority_aggregation, false ); + _Thread_Set_scheduler_node_priority( + priority_aggregation, + PRIORITY_GROUP_LAST + ); _Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_ADD ); _Priority_Actions_add( priority_actions, priority_aggregation ); } @@ -73,7 +95,10 @@ static void _Thread_Priority_action_remove( the_thread = arg; _Thread_Scheduler_remove_wait_node( the_thread, scheduler_node ); - _Thread_Set_scheduler_node_priority( priority_aggregation, true ); + _Thread_Set_scheduler_node_priority( + priority_aggregation, + PRIORITY_GROUP_FIRST + ); _Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_REMOVE ); _Priority_Actions_add( priority_actions, priority_aggregation ); } @@ -81,12 +106,16 @@ static void _Thread_Priority_action_remove( static void _Thread_Priority_action_change( Priority_Aggregation *priority_aggregation, - bool prepend_it, + Priority_Group_order priority_group_order, Priority_Actions *priority_actions, void *arg ) { - _Thread_Set_scheduler_node_priority( priority_aggregation, prepend_it ); + (void) arg; + _Thread_Set_scheduler_node_priority( + priority_aggregation, + priority_group_order + ); #if defined(RTEMS_SMP) || defined(RTEMS_DEBUG) _Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_CHANGE ); #endif @@ -97,7 +126,7 @@ static void _Thread_Priority_do_perform_actions( Thread_Control *the_thread, Thread_queue_Queue *queue, const Thread_queue_Operations *operations, - bool prepend_it, + Priority_Group_order priority_group_order, Thread_queue_Context *queue_context ) { @@ -107,11 +136,15 @@ static void _Thread_Priority_do_perform_actions( priority_aggregation = _Priority_Actions_move( &queue_context->Priority.Actions ); do { +#if defined(RTEMS_SMP) Priority_Aggregation *next_aggregation; +#endif Priority_Node *priority_action_node; Priority_Action_type priority_action_type; +#if defined(RTEMS_SMP) next_aggregation = _Priority_Get_next_action( priority_aggregation ); +#endif priority_action_node = priority_aggregation->Action.node; priority_action_type = priority_aggregation->Action.type; @@ -162,7 +195,7 @@ static void _Thread_Priority_do_perform_actions( _Priority_Changed( priority_aggregation, priority_action_node, - prepend_it, + priority_group_order, &queue_context->Priority.Actions, _Thread_Priority_action_change, NULL @@ -170,8 +203,12 @@ static void _Thread_Priority_do_perform_actions( break; } +#if defined(RTEMS_SMP) priority_aggregation = next_aggregation; - } while ( _Priority_Actions_is_valid( priority_aggregation ) ); + } while ( priority_aggregation != NULL ); +#else + } while ( false ); +#endif if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) { _Thread_queue_Context_add_priority_update( queue_context, the_thread ); @@ -203,7 +240,7 @@ void _Thread_Priority_perform_actions( */ the_thread = start_of_path; - update_count = _Thread_queue_Context_save_priority_updates( queue_context ); + update_count = _Thread_queue_Context_get_priority_updates( queue_context ); while ( true ) { Thread_queue_Queue *queue; @@ -214,7 +251,7 @@ void _Thread_Priority_perform_actions( the_thread, queue, the_thread->Wait.operations, - false, + PRIORITY_GROUP_LAST, queue_context ); @@ -244,7 +281,7 @@ static void _Thread_Priority_apply( Thread_Control *the_thread, Priority_Node *priority_action_node, Thread_queue_Context *queue_context, - bool prepend_it, + Priority_Group_order priority_group_order, Priority_Action_type priority_action_type ) { @@ -263,17 +300,17 @@ static void _Thread_Priority_apply( the_thread, queue, the_thread->Wait.operations, - prepend_it, + priority_group_order, queue_context ); if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) { #if defined(RTEMS_SMP) - _Thread_queue_Path_acquire_critical( queue, the_thread, queue_context ); + (void) _Thread_queue_Path_acquire( queue, the_thread, queue_context ); #endif _Thread_Priority_perform_actions( queue->owner, queue_context ); #if defined(RTEMS_SMP) - _Thread_queue_Path_release_critical( queue_context ); + _Thread_queue_Path_release( queue_context ); #endif } } @@ -288,7 +325,7 @@ void _Thread_Priority_add( the_thread, priority_node, queue_context, - false, + PRIORITY_GROUP_LAST, PRIORITY_ACTION_ADD ); } @@ -303,7 +340,7 @@ void _Thread_Priority_remove( the_thread, priority_node, queue_context, - true, + PRIORITY_GROUP_FIRST, PRIORITY_ACTION_REMOVE ); } @@ -311,7 +348,7 @@ void _Thread_Priority_remove( void _Thread_Priority_changed( Thread_Control *the_thread, Priority_Node *priority_node, - bool prepend_it, + Priority_Group_order priority_group_order, Thread_queue_Context *queue_context ) { @@ -319,11 +356,12 @@ void _Thread_Priority_changed( the_thread, priority_node, queue_context, - prepend_it, + priority_group_order, PRIORITY_ACTION_CHANGE ); } +#if defined(RTEMS_SMP) void _Thread_Priority_replace( Thread_Control *the_thread, Priority_Node *victim_node, @@ -339,6 +377,7 @@ void _Thread_Priority_replace( replacement_node ); } +#endif void _Thread_Priority_update( Thread_queue_Context *queue_context ) { @@ -363,18 +402,140 @@ void _Thread_Priority_update( Thread_queue_Context *queue_context ) } #if defined(RTEMS_SMP) -void _Thread_Priority_and_sticky_update( +static void _Thread_Priority_update_helping( Thread_Control *the_thread, - int sticky_level_change + Chain_Node *first_node ) { - ISR_lock_Context lock_context; + const Chain_Node *tail; + Chain_Node *node; + + tail = _Chain_Immutable_tail( &the_thread->Scheduler.Scheduler_nodes ); + node = _Chain_Next( first_node ); + + while ( node != tail ) { + Scheduler_Node *scheduler_node; + const Scheduler_Control *scheduler; + ISR_lock_Context lock_context; + + scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node ); + scheduler = _Scheduler_Node_get_scheduler( scheduler_node ); + + _Scheduler_Acquire_critical( scheduler, &lock_context ); + ( *scheduler->Operations.update_priority )( + scheduler, + the_thread, + scheduler_node + ); + _Scheduler_Release_critical( scheduler, &lock_context ); + + node = _Chain_Next( node ); + } +} + +void _Thread_Priority_update_and_make_sticky( Thread_Control *the_thread ) +{ + ISR_lock_Context lock_context; + ISR_lock_Context lock_context_2; + Chain_Node *node; + Scheduler_Node *scheduler_node; + const Scheduler_Control *scheduler; + int new_sticky_level; + int make_sticky_level; _Thread_State_acquire( the_thread, &lock_context ); - _Scheduler_Priority_and_sticky_update( + _Thread_Scheduler_process_requests( the_thread ); + + node = _Chain_First( &the_thread->Scheduler.Scheduler_nodes ); + scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node ); + scheduler = _Scheduler_Node_get_scheduler( scheduler_node ); + + _Scheduler_Acquire_critical( scheduler, &lock_context_2 ); + + new_sticky_level = scheduler_node->sticky_level + 1; + scheduler_node->sticky_level = new_sticky_level; + _Assert( new_sticky_level >= 1 ); + + /* + * The sticky level is incremented by the scheduler block operation, so for a + * ready thread, the change to sticky happens at a level of two. + */ + make_sticky_level = 1 + (int) _Thread_Is_ready( the_thread ); + + if ( new_sticky_level == make_sticky_level ) { + ( *scheduler->Operations.make_sticky )( + scheduler, + the_thread, + scheduler_node + ); + } + + ( *scheduler->Operations.update_priority )( + scheduler, + the_thread, + scheduler_node + ); + + _Scheduler_Release_critical( scheduler, &lock_context_2 ); + _Thread_Priority_update_helping( the_thread, node ); + _Thread_State_release( the_thread, &lock_context ); +} + +void _Thread_Priority_update_and_clean_sticky( Thread_Control *the_thread ) +{ + ISR_lock_Context lock_context; + ISR_lock_Context lock_context_2; + Chain_Node *node; + Scheduler_Node *scheduler_node; + const Scheduler_Control *scheduler; + int new_sticky_level; + int clean_sticky_level; + + _Thread_State_acquire( the_thread, &lock_context ); + _Thread_Scheduler_process_requests( the_thread ); + + node = _Chain_First( &the_thread->Scheduler.Scheduler_nodes ); + scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node ); + scheduler = _Scheduler_Node_get_scheduler( scheduler_node ); + + _Scheduler_Acquire_critical( scheduler, &lock_context_2 ); + + new_sticky_level = scheduler_node->sticky_level - 1; + scheduler_node->sticky_level = new_sticky_level; + _Assert( new_sticky_level >= 0 ); + + /* + * The sticky level is incremented by the scheduler block operation, so for a + * ready thread, the change to sticky happens at a level of one. + */ + clean_sticky_level = (int) _Thread_Is_ready( the_thread ); + + if ( new_sticky_level == clean_sticky_level ) { + ( *scheduler->Operations.clean_sticky )( + scheduler, + the_thread, + scheduler_node + ); + } + + ( *scheduler->Operations.update_priority )( + scheduler, the_thread, - sticky_level_change + scheduler_node ); + + _Scheduler_Release_critical( scheduler, &lock_context_2 ); + _Thread_Priority_update_helping( the_thread, node ); + _Thread_State_release( the_thread, &lock_context ); +} + +void _Thread_Priority_update_ignore_sticky( Thread_Control *the_thread ) +{ + ISR_lock_Context lock_context; + + _Thread_State_acquire( the_thread, &lock_context ); + _Thread_Scheduler_process_requests( the_thread ); + _Scheduler_Update_priority( the_thread ); _Thread_State_release( the_thread, &lock_context ); } #endif |