From 33e250c9fa370f620ddbc5850342d5a90b123524 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 27 May 2016 15:41:41 +0200 Subject: score: Rework CORE priority ceiling mutex Rework seize and surrender methods to use CORE_ceiling_mutex_Control. This eliminates CORE_mutex_Disciplines. --- cpukit/score/include/rtems/score/coremuteximpl.h | 250 ++++++++++++++++------- 1 file changed, 180 insertions(+), 70 deletions(-) (limited to 'cpukit/score/include/rtems/score/coremuteximpl.h') diff --git a/cpukit/score/include/rtems/score/coremuteximpl.h b/cpukit/score/include/rtems/score/coremuteximpl.h index fc2ffd9020..f459743346 100644 --- a/cpukit/score/include/rtems/score/coremuteximpl.h +++ b/cpukit/score/include/rtems/score/coremuteximpl.h @@ -127,42 +127,6 @@ RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_locked( return _CORE_mutex_Get_owner( the_mutex ) != NULL; } -/** - * @brief Does mutex use priority inheritance. - * - * This routine returns true if the mutex's wait discipline is - * INHERIT_PRIORITY and false otherwise. - * - * @param[in] the_attribute is the attribute set of the mutex. - * - * @retval true The mutex is using priority inheritance. - * @retval false The mutex is not using priority inheritance. - */ -RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_inherit_priority( - const CORE_mutex_Attributes *the_attribute -) -{ - return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT; -} - -/** - * @brief Does mutex use priority ceiling. - * - * This routine returns true if the mutex's wait discipline is - * PRIORITY_CEILING and false otherwise. - * - * @param[in] the_attribute is the attribute set of the mutex. - * - * @retval true The mutex is using priority ceiling. - * @retval false The mutex is not using priority ceiling. - */ -RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_priority_ceiling( - const CORE_mutex_Attributes *the_attribute -) -{ - return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING; -} - /** * @brief Attempt to receive a unit from the_mutex. * @@ -191,40 +155,7 @@ RTEMS_INLINE_ROUTINE Status_Control _CORE_mutex_Seize_interrupt_trylock( the_mutex->nest_count = 1; ++executing->resource_count; - if ( !_CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ) { - _CORE_mutex_Release( the_mutex, queue_context ); - } else { - /* - * must be CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING - * - * we possibly bump the priority of the current holder -- which - * happens to be _Thread_Executing. - */ - Priority_Control ceiling; - Priority_Control current; - - ceiling = the_mutex->Attributes.priority_ceiling; - current = executing->current_priority; - if ( current == ceiling ) { - _CORE_mutex_Release( the_mutex, queue_context ); - } else if ( current > ceiling ) { - Per_CPU_Control *cpu_self; - - cpu_self = _Thread_Dispatch_disable_critical( - &queue_context->Lock_context - ); - _CORE_mutex_Release( the_mutex, queue_context ); - _Thread_Raise_priority( executing, ceiling ); - _Thread_Dispatch_enable( cpu_self ); - } else /* if ( current < ceiling ) */ { - the_mutex->holder = NULL; - the_mutex->nest_count = 0; /* undo locking above */ - executing->resource_count--; /* undo locking above */ - _CORE_mutex_Release( the_mutex, queue_context ); - return STATUS_MUTEX_CEILING_VIOLATED; - } - } - + _CORE_mutex_Release( the_mutex, queue_context ); return STATUS_SUCCESSFUL; } @@ -345,6 +276,32 @@ RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_owner( return _CORE_mutex_Get_owner( the_mutex ) == the_thread; } +RTEMS_INLINE_ROUTINE void _CORE_mutex_Restore_priority( + Thread_Control *executing +) +{ + /* + * Whether or not someone is waiting for the mutex, an + * inherited priority must be lowered if this is the last + * mutex (i.e. resource) this task has. + */ + if ( !_Thread_Owns_resources( executing ) ) { + /* + * Ensure that the executing resource count is visible to all other + * processors and that we read the latest priority restore hint. + */ + _Atomic_Fence( ATOMIC_ORDER_ACQ_REL ); + + if ( executing->priority_restore_hint ) { + Per_CPU_Control *cpu_self; + + cpu_self = _Thread_Dispatch_disable(); + _Thread_Restore_priority( executing ); + _Thread_Dispatch_enable( cpu_self ); + } + } +} + RTEMS_INLINE_ROUTINE void _CORE_recursive_mutex_Initialize( CORE_recursive_mutex_Control *the_mutex ) @@ -479,6 +436,159 @@ RTEMS_INLINE_ROUTINE void _CORE_recursive_mutex_Surrender_no_protocol_classic( ); } +RTEMS_INLINE_ROUTINE void _CORE_ceiling_mutex_Initialize( + CORE_ceiling_mutex_Control *the_mutex, + Priority_Control priority_ceiling +) +{ + _CORE_recursive_mutex_Initialize( &the_mutex->Recursive ); + the_mutex->priority_ceiling = priority_ceiling; +} + +RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Set_owner( + CORE_ceiling_mutex_Control *the_mutex, + Thread_Control *owner, + Thread_queue_Context *queue_context +) +{ + Priority_Control priority_ceiling; + Priority_Control current_priority; + Per_CPU_Control *cpu_self; + + priority_ceiling = the_mutex->priority_ceiling; + current_priority = owner->current_priority; + + if ( current_priority < priority_ceiling ) { + _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context ); + return STATUS_MUTEX_CEILING_VIOLATED; + } + + _CORE_mutex_Set_owner( &the_mutex->Recursive.Mutex, owner ); + ++owner->resource_count; + + if ( current_priority == priority_ceiling ) { + _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context ); + return STATUS_SUCCESSFUL; + } + + cpu_self = _Thread_Dispatch_disable_critical( &queue_context->Lock_context ); + _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context ); + _Thread_Raise_priority( owner, priority_ceiling ); + _Thread_Dispatch_enable( cpu_self ); + return STATUS_SUCCESSFUL; +} + +RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Seize( + CORE_ceiling_mutex_Control *the_mutex, + Thread_Control *executing, + bool wait, + Watchdog_Interval timeout, + Status_Control ( *nested )( CORE_recursive_mutex_Control * ), + Thread_queue_Context *queue_context +) +{ + Thread_Control *owner; + + _CORE_mutex_Acquire_critical( &the_mutex->Recursive.Mutex, queue_context ); + + owner = _CORE_mutex_Get_owner( &the_mutex->Recursive.Mutex ); + + if ( owner == NULL ) { + return _CORE_ceiling_mutex_Set_owner( + the_mutex, + executing, + queue_context + ); + } + + if ( owner == executing ) { + Status_Control status; + + status = ( *nested )( &the_mutex->Recursive ); + _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context ); + return status; + } + + return _CORE_mutex_Seize_no_protocol_slow( + &the_mutex->Recursive.Mutex, + CORE_MUTEX_TQ_OPERATIONS, + executing, + wait, + timeout, + queue_context + ); +} + +RTEMS_INLINE_ROUTINE Status_Control _CORE_ceiling_mutex_Surrender( + CORE_ceiling_mutex_Control *the_mutex, + Thread_Control *executing, + Thread_queue_Context *queue_context +) +{ + unsigned int nest_level; + Thread_Control *new_owner; + + _CORE_mutex_Acquire_critical( &the_mutex->Recursive.Mutex, queue_context ); + + if ( !_CORE_mutex_Is_owner( &the_mutex->Recursive.Mutex, executing ) ) { + _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context ); + return STATUS_NOT_OWNER; + } + + nest_level = the_mutex->Recursive.nest_level; + + if ( nest_level > 0 ) { + the_mutex->Recursive.nest_level = nest_level - 1; + _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context ); + return STATUS_SUCCESSFUL; + } + + --executing->resource_count; + + new_owner = _Thread_queue_First_locked( + &the_mutex->Recursive.Mutex.Wait_queue, + CORE_MUTEX_TQ_OPERATIONS + ); + _CORE_mutex_Set_owner( &the_mutex->Recursive.Mutex, new_owner ); + + if ( new_owner != NULL ) { + bool unblock; + + /* + * We must extract the thread now since this will restore its default + * thread lock. This is necessary to avoid a deadlock in the + * _Thread_Change_priority() below due to a recursive thread queue lock + * acquire. + */ + unblock = _Thread_queue_Extract_locked( + &the_mutex->Recursive.Mutex.Wait_queue.Queue, + CORE_MUTEX_TQ_OPERATIONS, + new_owner, + queue_context + ); + +#if defined(RTEMS_MULTIPROCESSING) + if ( _Objects_Is_local_id( new_owner->Object.id ) ) +#endif + { + ++new_owner->resource_count; + _Thread_Raise_priority( new_owner, the_mutex->priority_ceiling ); + } + + _Thread_queue_Unblock_critical( + unblock, + &the_mutex->Recursive.Mutex.Wait_queue.Queue, + new_owner, + &queue_context->Lock_context + ); + } else { + _CORE_mutex_Release( &the_mutex->Recursive.Mutex, queue_context ); + } + + _CORE_mutex_Restore_priority( executing ); + return STATUS_SUCCESSFUL; +} + /** @} */ #ifdef __cplusplus -- cgit v1.2.3