/* * Thread Priority Node * * Copyright (C) 2017. Gedare Bloom. * * 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. */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include /** * This routine adds a thread's Priority_node to the mutex holder's * Inherited_priorities list, and sets the waiting_to_hold field to the * mutex. * * Returns true if the enqueued node is at the head of the holder's * Inherited priorities, and therefore the holder's priority may change. */ bool _Thread_Enqueue_priority_node( Thread_Control *the_thread, CORE_mutex_Control *the_mutex ) { Chain_Node *iter; Thread_Priority_node *thread_pn, *holder_pn; Priority_Control task_priority, iter_priority; thread_pn = &the_thread->Priority_node; holder_pn = &the_mutex->holder->Priority_node; thread_pn->waiting_to_hold = the_mutex; iter = holder_pn->Inherited_priorities.first; task_priority = thread_pn->current_priority; /* Find the first node in holder's Inherited_priorities list with * lower priority than the task, or find the end of the list. */ while ( !_Chain_Is_tail( &holder_pn->Inherited_priorities, iter) ) { iter_priority = ((Thread_Priority_node *)iter)->current_priority; if ( iter_priority > task_priority ) { break; } iter = _Chain_Next( iter ); } _Chain_Insert_unprotected( _Chain_Previous( iter ), &thread_pn->Node ); /* If the_thread is at the start of the holder's Inherited_priorites list, * then may need to update the holder's current priority. */ if ( _Chain_Is_first( &thread_pn->Node ) ) { return true; } return false; } /** * This routine sets the thread's priority_node->current_priority to the * minimum of the real_priority and the first node of Inherited_priorities, * if any. */ void _Thread_Evaluate_priority( Thread_Control *the_thread ) { Chain_Node *first; Thread_Priority_node *first_pn, *priority_node; Priority_Control current_priority, min_priority; /* Start with the_thread, and iterate through the holder threads that * the_thread is waiting on. If any thread's priority does not change, * then stop iterating. */ while ( the_thread != NULL ) { priority_node = &the_thread->Priority_node; current_priority = priority_node->current_priority; min_priority = priority_node->real_priority; first = _Chain_First( &priority_node->Inherited_priorities ); if ( !_Chain_Is_tail( &priority_node->Inherited_priorities, first ) ) { first_pn = (Thread_Priority_node *)first; if ( min_priority > first_pn->current_priority ) { min_priority = first_pn->current_priority; } } if ( current_priority < min_priority ) { _Thread_Change_priority( the_thread, min_priority, true ); } else if ( current_priority > min_priority ) { _Thread_Change_priority( the_thread, min_priority, false ); } else { break; } if ( the_thread->Priority_node.waiting_to_hold != NULL ) { the_thread = the_thread->Priority_node.waiting_to_hold->holder; } else { the_thread = NULL; } } } /** * This routine removes a thread's Priority_node from an * Inherited_priorities list, updates the mutex holder's * current_priority if needed, and clears the mutex field. * * Returns the mutex that the_thread was waiting on. */ CORE_mutex_Control* _Thread_Dequeue_priority_node( Thread_Priority_node *thread_pn ) { CORE_mutex_Control *the_mutex = thread_pn->waiting_to_hold; if ( the_mutex == NULL ) { return NULL; } _Chain_Extract_unprotected( &thread_pn->Node ); thread_pn->waiting_to_hold = NULL; return the_mutex; } void _Thread_Requeue_priority_node( Thread_Control *the_thread ) { ISR_Level level; CORE_mutex_Control *mutex; _ISR_Disable( level ); /* TODO: refactor? */ mutex = _Thread_Dequeue_priority_node( &the_thread->Priority_node ); if ( mutex != NULL ) { _Thread_Enqueue_priority_node( the_thread, mutex ); } _ISR_Enable( level ); } /** * This routine removes the inherited priorities from the mutex being * released and updates the holder's priority if necessary. */ void _Thread_Release_inherited_priority( CORE_mutex_Control *the_mutex ) { Chain_Control *ip = &the_mutex->holder->Priority_node.Inherited_priorities; Chain_Node *cn; Thread_Priority_node *tpn; for (cn = _Chain_First(ip); !_Chain_Is_tail(ip, cn); cn = _Chain_Next(cn)) { tpn = (Thread_Priority_node*)cn; if ( tpn->waiting_to_hold == the_mutex ) { _Chain_Extract(cn); tpn->waiting_to_hold = NULL; } } _Thread_Evaluate_priority( the_mutex->holder ); }