From 5a598ac99b0de720a04afc5e2ac6764117589b90 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 27 May 2016 08:02:03 +0200 Subject: score: Add CORE mutex variants Add CORE_recursive_mutex_Control and CORE_ceiling_mutex_Control to avoid the run-time evaluation of attributes to figure out how a particular mutex methods should behave. Start with the no protocol variants. This eliminates the CORE_MUTEX_DISCIPLINES_FIFO and CORE_MUTEX_DISCIPLINES_PRIORITY disciplines. --- cpukit/score/include/rtems/score/coremutex.h | 43 ++++-- cpukit/score/include/rtems/score/coremuteximpl.h | 177 ++++++++++++++++++++--- cpukit/score/src/apimutex.c | 1 - cpukit/score/src/coremutex.c | 57 ++++---- cpukit/score/src/coremutexseize.c | 27 +++- cpukit/score/src/coremutexsurrender.c | 28 +--- 6 files changed, 247 insertions(+), 86 deletions(-) (limited to 'cpukit/score') diff --git a/cpukit/score/include/rtems/score/coremutex.h b/cpukit/score/include/rtems/score/coremutex.h index f8694095ac..173bb2efa6 100644 --- a/cpukit/score/include/rtems/score/coremutex.h +++ b/cpukit/score/include/rtems/score/coremutex.h @@ -47,10 +47,6 @@ extern "C" { * This enumerated type defines the blocking disciplines for a mutex. */ typedef enum { - /** This specifies that threads will wait for the mutex in FIFO order. */ - CORE_MUTEX_DISCIPLINES_FIFO, - /** This specifies that threads will wait for the mutex in priority order. */ - CORE_MUTEX_DISCIPLINES_PRIORITY, /** This specifies that threads will wait for the mutex in priority order. * Additionally, the Priority Inheritance Protocol will be in effect. */ @@ -100,10 +96,6 @@ typedef struct { * be when attempting to acquire the mutex when it is already locked. */ CORE_mutex_Nesting_behaviors lock_nesting_behavior; - /** When this field is true, then only the thread that locked the mutex - * is allowed to unlock it. - */ - bool only_owner_release; /** This field indicates whether threads waiting on the mutex block in * FIFO or priority order. */ @@ -125,11 +117,6 @@ typedef struct { */ Thread_queue_Control Wait_queue; - /** - * @brief The thread queue operations according to the blocking discipline. - */ - const Thread_queue_Operations *operations; - /** This element is the set of attributes which define this instance's * behavior. */ @@ -145,6 +132,36 @@ typedef struct { Thread_Control *holder; } CORE_mutex_Control; +/** + * @brief The recursive mutex control. + */ +typedef struct { + /** + * @brief The plain non-recursive mutex. + */ + CORE_mutex_Control Mutex; + + /** + * @brief The nest level in case of a recursive seize. + */ + unsigned int nest_level; +} CORE_recursive_mutex_Control; + +/** + * @brief The recursive mutex control with priority ceiling protocol support. + */ +typedef struct { + /** + * @brief The plain recursive mutex. + */ + CORE_recursive_mutex_Control Recursive; + + /** + * @brief The priority ceiling value for the mutex owner. + */ + Priority_Control priority_ceiling; +} CORE_ceiling_mutex_Control; + /**@}*/ #ifdef __cplusplus diff --git a/cpukit/score/include/rtems/score/coremuteximpl.h b/cpukit/score/include/rtems/score/coremuteximpl.h index f8869b0a42..fc2ffd9020 100644 --- a/cpukit/score/include/rtems/score/coremuteximpl.h +++ b/cpukit/score/include/rtems/score/coremuteximpl.h @@ -33,6 +33,8 @@ extern "C" { */ /**@{**/ +#define CORE_MUTEX_TQ_OPERATIONS &_Thread_queue_Operations_priority + /** * @brief Initializes the mutex based on the parameters passed. * @@ -100,6 +102,13 @@ Status_Control _CORE_mutex_Seize_interrupt_blocking( Thread_queue_Context *queue_context ); +RTEMS_INLINE_ROUTINE Thread_Control *_CORE_mutex_Get_owner( + const CORE_mutex_Control *the_mutex +) +{ + return the_mutex->holder; +} + /** * @brief Is mutex locked. * @@ -115,7 +124,7 @@ RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_locked( const CORE_mutex_Control *the_mutex ) { - return the_mutex->holder != NULL; + return _CORE_mutex_Get_owner( the_mutex ) != NULL; } /** @@ -180,10 +189,7 @@ RTEMS_INLINE_ROUTINE Status_Control _CORE_mutex_Seize_interrupt_trylock( if ( !_CORE_mutex_Is_locked( the_mutex ) ) { the_mutex->holder = executing; the_mutex->nest_count = 1; - if ( _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) || - _CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ){ - executing->resource_count++; - } + ++executing->resource_count; if ( !_CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ) { _CORE_mutex_Release( the_mutex, queue_context ); @@ -309,35 +315,168 @@ RTEMS_INLINE_ROUTINE Status_Control _CORE_mutex_Seize( ); } +Status_Control _CORE_mutex_Seize_no_protocol_slow( + CORE_mutex_Control *the_mutex, + const Thread_queue_Operations *operations, + Thread_Control *executing, + bool wait, + Watchdog_Interval timeout, + Thread_queue_Context *queue_context +); + Status_Control _CORE_mutex_Surrender( CORE_mutex_Control *the_mutex, Thread_queue_Context *queue_context ); +RTEMS_INLINE_ROUTINE void _CORE_mutex_Set_owner( + CORE_mutex_Control *the_mutex, + Thread_Control *owner +) +{ + the_mutex->holder = owner; +} + RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_owner( const CORE_mutex_Control *the_mutex, const Thread_Control *the_thread ) { - return the_mutex->holder == the_thread; + return _CORE_mutex_Get_owner( the_mutex ) == the_thread; } -/** - * @brief Does core mutex use FIFO blocking. - * - * This routine returns true if the mutex's wait discipline is FIFO and false - * otherwise. - * - * @param[in] the_attribute is the attribute set of the mutex. - * - * @retval true The mutex is using FIFO blocking order. - * @retval false The mutex is not using FIFO blocking order. +RTEMS_INLINE_ROUTINE void _CORE_recursive_mutex_Initialize( + CORE_recursive_mutex_Control *the_mutex +) +{ + _Thread_queue_Initialize( &the_mutex->Mutex.Wait_queue ); + the_mutex->Mutex.holder = NULL; + the_mutex->nest_level = 0; +} + +RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Seize_nested( + CORE_recursive_mutex_Control *the_mutex +) +{ + ++the_mutex->nest_level; + return STATUS_SUCCESSFUL; +} + +RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Seize_no_protocol( + CORE_recursive_mutex_Control *the_mutex, + const Thread_queue_Operations *operations, + 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->Mutex, queue_context ); + + owner = _CORE_mutex_Get_owner( &the_mutex->Mutex ); + + if ( owner == NULL ) { + _CORE_mutex_Set_owner( &the_mutex->Mutex, executing ); + _CORE_mutex_Release( &the_mutex->Mutex, queue_context ); + return STATUS_SUCCESSFUL; + } + + if ( owner == executing ) { + Status_Control status; + + status = ( *nested )( the_mutex ); + _CORE_mutex_Release( &the_mutex->Mutex, queue_context ); + return status; + } + + return _CORE_mutex_Seize_no_protocol_slow( + &the_mutex->Mutex, + operations, + executing, + wait, + timeout, + queue_context + ); +} + +RTEMS_INLINE_ROUTINE void +_CORE_recursive_mutex_Surrender_no_protocol_finalize( + CORE_recursive_mutex_Control *the_mutex, + const Thread_queue_Operations *operations, + Thread_queue_Context *queue_context +) +{ + unsigned int nest_level; + Thread_Control *new_owner; + + nest_level = the_mutex->nest_level; + + if ( nest_level > 0 ) { + the_mutex->nest_level = nest_level - 1; + _CORE_mutex_Release( &the_mutex->Mutex, queue_context ); + return; + } + + new_owner = _Thread_queue_First_locked( + &the_mutex->Mutex.Wait_queue, + operations + ); + _CORE_mutex_Set_owner( &the_mutex->Mutex, new_owner ); + + if ( new_owner == NULL ) { + _CORE_mutex_Release( &the_mutex->Mutex, queue_context ); + return; + } + + _Thread_queue_Extract_critical( + &the_mutex->Mutex.Wait_queue.Queue, + operations, + new_owner, + queue_context + ); +} + +RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Surrender_no_protocol( + CORE_recursive_mutex_Control *the_mutex, + const Thread_queue_Operations *operations, + Thread_Control *executing, + Thread_queue_Context *queue_context +) +{ + _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context ); + + if ( !_CORE_mutex_Is_owner( &the_mutex->Mutex, executing ) ) { + _CORE_mutex_Release( &the_mutex->Mutex, queue_context ); + return STATUS_NOT_OWNER; + } + + _CORE_recursive_mutex_Surrender_no_protocol_finalize( + the_mutex, + operations, + queue_context + ); + return STATUS_SUCCESSFUL; +} + +/* + * The Classic no protocol recursive mutex has the nice property that everyone + * can release it. */ -RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_fifo( - const CORE_mutex_Attributes *the_attribute +RTEMS_INLINE_ROUTINE void _CORE_recursive_mutex_Surrender_no_protocol_classic( + CORE_recursive_mutex_Control *the_mutex, + const Thread_queue_Operations *operations, + Thread_queue_Context *queue_context ) { - return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_FIFO; + _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context ); + _CORE_recursive_mutex_Surrender_no_protocol_finalize( + the_mutex, + operations, + queue_context + ); } /** @} */ diff --git a/cpukit/score/src/apimutex.c b/cpukit/score/src/apimutex.c index a098edbd61..8af374aaef 100644 --- a/cpukit/score/src/apimutex.c +++ b/cpukit/score/src/apimutex.c @@ -49,7 +49,6 @@ void _API_Mutex_Allocate( CORE_mutex_Attributes attr = { CORE_MUTEX_NESTING_ACQUIRES, - true, CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT, 0 }; diff --git a/cpukit/score/src/coremutex.c b/cpukit/score/src/coremutex.c index ec073ff999..6f73c1bd16 100644 --- a/cpukit/score/src/coremutex.c +++ b/cpukit/score/src/coremutex.c @@ -39,42 +39,41 @@ Status_Control _CORE_mutex_Initialize( the_mutex->Attributes = *the_mutex_attributes; if ( initially_locked ) { - bool is_priority_ceiling = - _CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ); + bool is_priority_ceiling; + Priority_Control ceiling; + Per_CPU_Control *cpu_self; the_mutex->nest_count = 1; the_mutex->holder = executing; - if ( is_priority_ceiling || - _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) ) { - Priority_Control ceiling = the_mutex->Attributes.priority_ceiling; - Per_CPU_Control *cpu_self; - - /* The mutex initialization is only protected by the allocator lock */ - cpu_self = _Thread_Dispatch_disable(); + /* The mutex initialization is only protected by the allocator lock */ + cpu_self = _Thread_Dispatch_disable(); + is_priority_ceiling = + _CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ); + ceiling = the_mutex->Attributes.priority_ceiling; + + /* + * The test to check for a ceiling violation is a bit arbitrary. In case + * this thread is the owner of a priority inheritance mutex, then it may + * get a higher priority later or anytime on SMP configurations. + */ + if ( is_priority_ceiling && executing->current_priority < ceiling ) { /* - * The test to check for a ceiling violation is a bit arbitrary. In case - * this thread is the owner of a priority inheritance mutex, then it may - * get a higher priority later or anytime on SMP configurations. + * There is no need to undo the previous work since this error aborts + * the object creation. */ - if ( is_priority_ceiling && executing->current_priority < ceiling ) { - /* - * There is no need to undo the previous work since this error aborts - * the object creation. - */ - _Thread_Dispatch_enable( cpu_self ); - return STATUS_MUTEX_CEILING_VIOLATED; - } - - executing->resource_count++; + _Thread_Dispatch_enable( cpu_self ); + return STATUS_MUTEX_CEILING_VIOLATED; + } - if ( is_priority_ceiling ) { - _Thread_Raise_priority( executing, ceiling ); - } + executing->resource_count++; - _Thread_Dispatch_enable( cpu_self ); + if ( is_priority_ceiling ) { + _Thread_Raise_priority( executing, ceiling ); } + + _Thread_Dispatch_enable( cpu_self ); } else { the_mutex->nest_count = 0; the_mutex->holder = NULL; @@ -82,11 +81,5 @@ Status_Control _CORE_mutex_Initialize( _Thread_queue_Initialize( &the_mutex->Wait_queue ); - if ( _CORE_mutex_Is_fifo( the_mutex_attributes ) ) { - the_mutex->operations = &_Thread_queue_Operations_FIFO; - } else { - the_mutex->operations = &_Thread_queue_Operations_priority; - } - return STATUS_SUCCESSFUL; } diff --git a/cpukit/score/src/coremutexseize.c b/cpukit/score/src/coremutexseize.c index 7b8b603d9b..596378fda6 100644 --- a/cpukit/score/src/coremutexseize.c +++ b/cpukit/score/src/coremutexseize.c @@ -68,7 +68,7 @@ Status_Control _CORE_mutex_Seize_interrupt_blocking( _Thread_queue_Enqueue_critical( &the_mutex->Wait_queue.Queue, - the_mutex->operations, + CORE_MUTEX_TQ_OPERATIONS, executing, STATES_WAITING_FOR_MUTEX, timeout, @@ -82,3 +82,28 @@ Status_Control _CORE_mutex_Seize_interrupt_blocking( return _Thread_Wait_get_status( executing ); } +Status_Control _CORE_mutex_Seize_no_protocol_slow( + CORE_mutex_Control *the_mutex, + const Thread_queue_Operations *operations, + Thread_Control *executing, + bool wait, + Watchdog_Interval timeout, + Thread_queue_Context *queue_context +) +{ + if ( wait ) { + _Thread_queue_Context_set_expected_level( queue_context, 1 ); + _Thread_queue_Enqueue_critical( + &the_mutex->Wait_queue.Queue, + operations, + executing, + STATES_WAITING_FOR_MUTEX, + timeout, + queue_context + ); + return _Thread_Wait_get_status( executing ); + } else { + _CORE_mutex_Release( the_mutex, queue_context ); + return STATUS_UNAVAILABLE; + } +} diff --git a/cpukit/score/src/coremutexsurrender.c b/cpukit/score/src/coremutexsurrender.c index 6047409085..2d976e0c22 100644 --- a/cpukit/score/src/coremutexsurrender.c +++ b/cpukit/score/src/coremutexsurrender.c @@ -34,18 +34,12 @@ Status_Control _CORE_mutex_Surrender( holder = the_mutex->holder; /* - * The following code allows a thread (or ISR) other than the thread - * which acquired the mutex to release that mutex. This is only - * allowed when the mutex in quetion is FIFO or simple Priority - * discipline. But Priority Ceiling or Priority Inheritance mutexes - * must be released by the thread which acquired them. + * Priority Ceiling or Priority Inheritance mutexes must be released by the + * thread which acquired them. */ - - if ( the_mutex->Attributes.only_owner_release ) { - if ( !_Thread_Is_executing( holder ) ) { - _ISR_lock_ISR_enable( &queue_context->Lock_context ); - return STATUS_NOT_OWNER; - } + if ( !_Thread_Is_executing( holder ) ) { + _ISR_lock_ISR_enable( &queue_context->Lock_context ); + return STATUS_NOT_OWNER; } _CORE_mutex_Acquire_critical( the_mutex, queue_context ); @@ -88,10 +82,7 @@ Status_Control _CORE_mutex_Surrender( * Formally release the mutex before possibly transferring it to a * blocked thread. */ - if ( _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) || - _CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ) { - holder->resource_count--; - } + holder->resource_count--; the_mutex->holder = NULL; /* @@ -101,7 +92,7 @@ Status_Control _CORE_mutex_Surrender( if ( ( the_thread = _Thread_queue_First_locked( &the_mutex->Wait_queue, - the_mutex->operations + CORE_MUTEX_TQ_OPERATIONS ) ) ) { @@ -118,7 +109,7 @@ Status_Control _CORE_mutex_Surrender( */ unblock = _Thread_queue_Extract_locked( &the_mutex->Wait_queue.Queue, - the_mutex->operations, + CORE_MUTEX_TQ_OPERATIONS, the_thread, queue_context ); @@ -128,9 +119,6 @@ Status_Control _CORE_mutex_Surrender( #endif { switch ( the_mutex->Attributes.discipline ) { - case CORE_MUTEX_DISCIPLINES_FIFO: - case CORE_MUTEX_DISCIPLINES_PRIORITY: - break; case CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT: the_thread->resource_count++; _Thread_queue_Boost_priority( &the_mutex->Wait_queue.Queue, the_thread ); -- cgit v1.2.3