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. --- cpukit/posix/include/rtems/posix/mutex.h | 33 ++- cpukit/posix/include/rtems/posix/muteximpl.h | 30 +++ cpukit/posix/src/mutexdestroy.c | 12 +- cpukit/posix/src/mutexgetprioceiling.c | 6 +- cpukit/posix/src/mutexinit.c | 63 ++++-- cpukit/posix/src/mutexlocksupp.c | 48 ++++- cpukit/posix/src/mutexsetprioceiling.c | 5 +- cpukit/posix/src/mutexunlock.c | 29 ++- cpukit/rtems/include/rtems/rtems/sem.h | 5 + cpukit/rtems/include/rtems/rtems/semimpl.h | 1 + cpukit/rtems/src/semcreate.c | 57 +++--- cpukit/rtems/src/semdelete.c | 2 + cpukit/rtems/src/semflush.c | 1 + cpukit/rtems/src/semobtain.c | 15 ++ cpukit/rtems/src/semrelease.c | 8 + cpukit/score/include/rtems/score/coremutex.h | 43 ++-- cpukit/score/include/rtems/score/coremuteximpl.h | 243 +++++++++++++++++++++-- cpukit/score/src/apimutex.c | 1 - cpukit/score/src/coremutex.c | 57 +++--- cpukit/score/src/coremutexseize.c | 21 +- cpukit/score/src/coremutexsurrender.c | 28 +-- 21 files changed, 550 insertions(+), 158 deletions(-)
diff --git a/cpukit/posix/include/rtems/posix/mutex.h b/cpukit/posix/include/rtems/posix/mutex.h index e1dfa34..71e7821 100644 --- a/cpukit/posix/include/rtems/posix/mutex.h +++ b/cpukit/posix/include/rtems/posix/mutex.h @@ -35,14 +35,35 @@ extern "C" { */ /**@{**/ -/* - * Data Structure used to manage a POSIX mutex +/** + * @brief The POSIX mutex control. */ - typedef struct { - Objects_Control Object; - CORE_mutex_Control Mutex; -} POSIX_Mutex_Control; + /** + * @brief The object control. + */ + Objects_Control Object; + + /** + * The most general mutex variant supported by a POSIX mutex. + * + * The priority inheritance or no protocol variants will use only parts of + * this structure. + */ + CORE_ceiling_mutex_Control Ceiling_mutex; + + /** + * @brief The protocol variant. + * + * @see POSIX_Mutex_Protocol. + */ + unsigned int protocol : 2; + + /** + * @brief Indicates if this is a non-recursive or recursive mutex. + */ + unsigned int is_recursive : 1; +} POSIX_Mutex_Control; /** @} */ diff --git a/cpukit/posix/include/rtems/posix/muteximpl.h b/cpukit/posix/include/rtems/posix/muteximpl.h index 30cc19d..769c8a5 100644 --- a/cpukit/posix/include/rtems/posix/muteximpl.h +++ b/cpukit/posix/include/rtems/posix/muteximpl.h @@ -28,6 +28,14 @@ extern "C" { #endif +#define POSIX_MUTEX_NO_PROTOCOL_TQ_OPERATIONS &_Thread_queue_Operations_FIFO + +typedef enum { + POSIX_MUTEX_NO_PROTOCOL, + POSIX_MUTEX_PRIORITY_INHERIT, + POSIX_MUTEX_PRIORITY_CEILING +} POSIX_Mutex_Protocol; + /** * The following defines the information control block used to manage * this class of objects. @@ -39,6 +47,28 @@ extern Objects_Information _POSIX_Mutex_Information; */ extern pthread_mutexattr_t _POSIX_Mutex_Default_attributes; +RTEMS_INLINE_ROUTINE void _POSIX_Mutex_Acquire_critical( + POSIX_Mutex_Control *the_mutex, + Thread_queue_Context *queue_context +) +{ + _CORE_mutex_Acquire_critical( + &the_mutex->Ceiling_mutex.Recursive_mutex.Mutex, + queue_context + ); +} + +RTEMS_INLINE_ROUTINE void _POSIX_Mutex_Release( + POSIX_Mutex_Control *the_mutex, + Thread_queue_Context *queue_context +) +{ + _CORE_mutex_Release( + &the_mutex->Ceiling_mutex.Recursive_mutex.Mutex, + queue_context + ); +} + /** * @brief POSIX Mutex Allocate * diff --git a/cpukit/posix/src/mutexdestroy.c b/cpukit/posix/src/mutexdestroy.c index 7fda7d3..c73f4fd 100644 --- a/cpukit/posix/src/mutexdestroy.c +++ b/cpukit/posix/src/mutexdestroy.c @@ -37,21 +37,23 @@ int pthread_mutex_destroy( the_mutex = _POSIX_Mutex_Get( mutex, &queue_context ); if ( the_mutex != NULL ) { - _CORE_mutex_Acquire_critical( &the_mutex->Mutex, &queue_context ); + _POSIX_Mutex_Acquire_critical( the_mutex, &queue_context ); /* * XXX: There is an error for the mutex being locked * or being in use by a condition variable. */ - if ( !_CORE_mutex_Is_locked( &the_mutex->Mutex ) ) { + if ( + !_CORE_mutex_Is_locked( &the_mutex->Ceiling_mutex.Recursive_mutex.Mutex ) + ) { _Objects_Close( &_POSIX_Mutex_Information, &the_mutex->Object ); - _CORE_mutex_Release( &the_mutex->Mutex, &queue_context ); - _CORE_mutex_Destroy( &the_mutex->Mutex ); + _POSIX_Mutex_Release( the_mutex, &queue_context ); + _CORE_mutex_Destroy( &the_mutex->Ceiling_mutex.Recursive_mutex.Mutex ); _POSIX_Mutex_Free( the_mutex ); eno = 0; } else { - _CORE_mutex_Release( &the_mutex->Mutex, &queue_context ); + _POSIX_Mutex_Release( the_mutex, &queue_context ); eno = EBUSY; } } else { diff --git a/cpukit/posix/src/mutexgetprioceiling.c b/cpukit/posix/src/mutexgetprioceiling.c index 268457a..b1ac757 100644 --- a/cpukit/posix/src/mutexgetprioceiling.c +++ b/cpukit/posix/src/mutexgetprioceiling.c @@ -43,13 +43,13 @@ int pthread_mutex_getprioceiling( return EINVAL; } - _CORE_mutex_Acquire_critical( &the_mutex->Mutex, &queue_context ); + _POSIX_Mutex_Acquire_critical( the_mutex, &queue_context ); *prioceiling = _POSIX_Priority_From_core( - the_mutex->Mutex.Attributes.priority_ceiling + the_mutex->Ceiling_mutex.Recursive_mutex.Mutex.Attributes.priority_ceiling ); - _CORE_mutex_Release( &the_mutex->Mutex, &queue_context ); + _POSIX_Mutex_Release( the_mutex, &queue_context ); return 0; } diff --git a/cpukit/posix/src/mutexinit.c b/cpukit/posix/src/mutexinit.c index d90b391..9fa9b35 100644 --- a/cpukit/posix/src/mutexinit.c +++ b/cpukit/posix/src/mutexinit.c @@ -33,10 +33,9 @@ int pthread_mutex_init( const pthread_mutexattr_t *attr ) { - POSIX_Mutex_Control *the_mutex; - CORE_mutex_Attributes *the_mutex_attr; - const pthread_mutexattr_t *the_attr; - CORE_mutex_Disciplines the_discipline; + POSIX_Mutex_Control *the_mutex; + const pthread_mutexattr_t *the_attr; + POSIX_Mutex_Protocol protocol; if ( attr ) the_attr = attr; else the_attr = &_POSIX_Mutex_Default_attributes; @@ -75,13 +74,13 @@ int pthread_mutex_init( */ switch ( the_attr->protocol ) { case PTHREAD_PRIO_NONE: - the_discipline = CORE_MUTEX_DISCIPLINES_FIFO; + protocol = POSIX_MUTEX_NO_PROTOCOL; break; case PTHREAD_PRIO_INHERIT: - the_discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT; + protocol = POSIX_MUTEX_PRIORITY_INHERIT; break; case PTHREAD_PRIO_PROTECT: - the_discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING; + protocol = POSIX_MUTEX_PRIORITY_CEILING; break; default: return EINVAL; @@ -117,21 +116,41 @@ int pthread_mutex_init( return EAGAIN; } - the_mutex_attr = &the_mutex->Mutex.Attributes; - - if ( the_attr->type == PTHREAD_MUTEX_RECURSIVE ) - the_mutex_attr->lock_nesting_behavior = CORE_MUTEX_NESTING_ACQUIRES; - else - the_mutex_attr->lock_nesting_behavior = CORE_MUTEX_NESTING_IS_ERROR; - the_mutex_attr->only_owner_release = true; - the_mutex_attr->priority_ceiling = - _POSIX_Priority_To_core( the_attr->prio_ceiling ); - the_mutex_attr->discipline = the_discipline; - - /* - * Must be initialized to unlocked. - */ - _CORE_mutex_Initialize( &the_mutex->Mutex, NULL, the_mutex_attr, false ); + the_mutex->protocol = protocol; + the_mutex->is_recursive = ( the_attr->type == PTHREAD_MUTEX_RECURSIVE ); + + if ( protocol == POSIX_MUTEX_NO_PROTOCOL ) { + _CORE_recursive_mutex_Initialize( + &the_mutex->Ceiling_mutex.Recursive_mutex + ); + } else { + CORE_mutex_Attributes the_mutex_attr; + + if ( the_attr->type == PTHREAD_MUTEX_RECURSIVE ) { + the_mutex_attr.lock_nesting_behavior = CORE_MUTEX_NESTING_ACQUIRES; + } else { + the_mutex_attr.lock_nesting_behavior = CORE_MUTEX_NESTING_IS_ERROR; + } + + the_mutex_attr.priority_ceiling = + _POSIX_Priority_To_core( the_attr->prio_ceiling ); + + if ( protocol == POSIX_MUTEX_PRIORITY_CEILING ) { + the_mutex_attr.discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING; + } else { + the_mutex_attr.discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT; + } + + /* + * Must be initialized to unlocked. + */ + _CORE_mutex_Initialize( + &the_mutex->Ceiling_mutex.Recursive_mutex.Mutex, + NULL, + &the_mutex_attr, + false + ); + } _Objects_Open_u32( &_POSIX_Mutex_Information, &the_mutex->Object, 0 ); diff --git a/cpukit/posix/src/mutexlocksupp.c b/cpukit/posix/src/mutexlocksupp.c index 6ecf87c..c500c8e 100644 --- a/cpukit/posix/src/mutexlocksupp.c +++ b/cpukit/posix/src/mutexlocksupp.c @@ -21,7 +21,10 @@ #include <rtems/posix/muteximpl.h> #include <rtems/posix/posixapi.h> -THREAD_QUEUE_OBJECT_ASSERT( POSIX_Mutex_Control, Mutex.Wait_queue ); +THREAD_QUEUE_OBJECT_ASSERT( + POSIX_Mutex_Control, + Ceiling_mutex.Recursive_mutex.Mutex.Wait_queue +); int _POSIX_Mutex_Lock_support( pthread_mutex_t *mutex, @@ -31,6 +34,7 @@ int _POSIX_Mutex_Lock_support( { POSIX_Mutex_Control *the_mutex; Thread_queue_Context queue_context; + Thread_Control *executing; Status_Control status; the_mutex = _POSIX_Mutex_Get( mutex, &queue_context ); @@ -39,12 +43,40 @@ int _POSIX_Mutex_Lock_support( return EINVAL; } - status = _CORE_mutex_Seize( - &the_mutex->Mutex, - _Thread_Executing, - blocking, - timeout, - &queue_context - ); + executing = _Thread_Executing; + + switch ( the_mutex->protocol ) { + case POSIX_MUTEX_NO_PROTOCOL: + if ( the_mutex->is_recursive ) { + status = _CORE_recursive_mutex_Seize_no_protocol( + &the_mutex->Ceiling_mutex.Recursive_mutex, + POSIX_MUTEX_NO_PROTOCOL_TQ_OPERATIONS, + executing, + blocking, + timeout, + &queue_context + ); + } else { + status = _CORE_mutex_Seize_no_protocol( + &the_mutex->Ceiling_mutex.Recursive_mutex.Mutex, + POSIX_MUTEX_NO_PROTOCOL_TQ_OPERATIONS, + executing, + blocking, + timeout, + &queue_context + ); + } + break; + default: + status = _CORE_mutex_Seize( + &the_mutex->Ceiling_mutex.Recursive_mutex.Mutex, + _Thread_Executing, + blocking, + timeout, + &queue_context + ); + break; + } + return _POSIX_Get_error( status ); } diff --git a/cpukit/posix/src/mutexsetprioceiling.c b/cpukit/posix/src/mutexsetprioceiling.c index 20f14dc..f17375a 100644 --- a/cpukit/posix/src/mutexsetprioceiling.c +++ b/cpukit/posix/src/mutexsetprioceiling.c @@ -57,9 +57,10 @@ int pthread_mutex_setprioceiling( _Assert( the_mutex != NULL ); *old_ceiling = _POSIX_Priority_From_core( - the_mutex->Mutex.Attributes.priority_ceiling + the_mutex->Ceiling_mutex.Recursive_mutex.Mutex.Attributes.priority_ceiling ); - the_mutex->Mutex.Attributes.priority_ceiling = the_priority; + the_mutex->Ceiling_mutex.Recursive_mutex.Mutex.Attributes.priority_ceiling = + the_priority; error = pthread_mutex_unlock( mutex ); _Assert( error == 0 ); diff --git a/cpukit/posix/src/mutexunlock.c b/cpukit/posix/src/mutexunlock.c index 1c3f2d8..3718603 100644 --- a/cpukit/posix/src/mutexunlock.c +++ b/cpukit/posix/src/mutexunlock.c @@ -33,6 +33,7 @@ int pthread_mutex_unlock( { POSIX_Mutex_Control *the_mutex; Thread_queue_Context queue_context; + Thread_Control *executing; Status_Control status; the_mutex = _POSIX_Mutex_Get( mutex, &queue_context ); @@ -41,6 +42,32 @@ int pthread_mutex_unlock( return EINVAL; } - status = _CORE_mutex_Surrender( &the_mutex->Mutex, &queue_context ); + executing = _Thread_Executing; + + switch ( the_mutex->protocol ) { + case POSIX_MUTEX_NO_PROTOCOL: + if ( the_mutex->is_recursive ) { + status = _CORE_recursive_mutex_Surrender_no_protocol( + &the_mutex->Ceiling_mutex.Recursive_mutex, + POSIX_MUTEX_NO_PROTOCOL_TQ_OPERATIONS, + executing, + &queue_context + ); + } else { + status = _CORE_mutex_Surrender_no_protocol( + &the_mutex->Ceiling_mutex.Recursive_mutex.Mutex, + POSIX_MUTEX_NO_PROTOCOL_TQ_OPERATIONS, + executing, + &queue_context + ); + } + break; + default: + status = _CORE_mutex_Surrender( + &the_mutex->Ceiling_mutex.Recursive_mutex.Mutex, + &queue_context + ); + break; + } return _POSIX_Get_error( status ); } diff --git a/cpukit/rtems/include/rtems/rtems/sem.h b/cpukit/rtems/include/rtems/rtems/sem.h index fe74f44..0faa04e 100644 --- a/cpukit/rtems/include/rtems/rtems/sem.h +++ b/cpukit/rtems/include/rtems/rtems/sem.h @@ -80,6 +80,11 @@ typedef struct { Thread_queue_Control Wait_queue; /** + * @brief The recursive mutex variant. + */ + CORE_recursive_mutex_Control Recursive_mutex; + + /** * This is the SuperCore Mutex instance associated with this Classic * API Semaphore instance. */ diff --git a/cpukit/rtems/include/rtems/rtems/semimpl.h b/cpukit/rtems/include/rtems/rtems/semimpl.h index f3dfa02..9ce85b0 100644 --- a/cpukit/rtems/include/rtems/rtems/semimpl.h +++ b/cpukit/rtems/include/rtems/rtems/semimpl.h @@ -28,6 +28,7 @@ extern "C" { typedef enum { SEMAPHORE_VARIANT_MUTEX, + SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL, SEMAPHORE_VARIANT_SIMPLE_BINARY, SEMAPHORE_VARIANT_COUNTING #if defined(RTEMS_SMP) diff --git a/cpukit/rtems/src/semcreate.c b/cpukit/rtems/src/semcreate.c index 455182b..5f28aa4 100644 --- a/cpukit/rtems/src/semcreate.c +++ b/cpukit/rtems/src/semcreate.c @@ -63,6 +63,7 @@ rtems_status_code rtems_semaphore_create( { Semaphore_Control *the_semaphore; CORE_mutex_Attributes the_mutex_attr; + Thread_Control *executing; Status_Control status; if ( !rtems_is_name_valid( name ) ) @@ -136,6 +137,7 @@ rtems_status_code rtems_semaphore_create( #endif the_semaphore->attribute_set = attribute_set; + executing = _Thread_Get_executing(); if ( _Attributes_Is_priority( attribute_set ) ) { the_semaphore->discipline = SEMAPHORE_DISCIPLINE_PRIORITY; @@ -163,43 +165,46 @@ rtems_status_code rtems_semaphore_create( status = _MRSP_Initialize( &the_semaphore->Core_control.mrsp, priority_ceiling, - _Thread_Get_executing(), + executing, count != 1 ); #endif - } else { - the_semaphore->variant = SEMAPHORE_VARIANT_MUTEX; + } else if ( + !_Attributes_Is_inherit_priority( attribute_set ) + && !_Attributes_Is_priority_ceiling( attribute_set ) + ) { + _Assert( _Attributes_Is_binary_semaphore( attribute_set ) ); + the_semaphore->variant = SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL; + _CORE_recursive_mutex_Initialize( + &the_semaphore->Core_control.Recursive_mutex + ); + + if ( count == 0 ) { + _CORE_recursive_mutex_Set_owner( + &the_semaphore->Core_control.Recursive_mutex, + executing + ); + } + status = STATUS_SUCCESSFUL; + } else { _Assert( _Attributes_Is_binary_semaphore( attribute_set ) ); + the_semaphore->variant = SEMAPHORE_VARIANT_MUTEX; - /* - * It is either simple binary semaphore or a more powerful mutex - * style binary semaphore. This is the mutex style. - */ - if ( _Attributes_Is_priority( attribute_set ) ) - the_mutex_attr.discipline = CORE_MUTEX_DISCIPLINES_PRIORITY; - else - the_mutex_attr.discipline = CORE_MUTEX_DISCIPLINES_FIFO; - - the_mutex_attr.priority_ceiling = _RTEMS_tasks_Priority_to_Core( - priority_ceiling - ); + the_mutex_attr.priority_ceiling = + _RTEMS_tasks_Priority_to_Core( priority_ceiling ); the_mutex_attr.lock_nesting_behavior = CORE_MUTEX_NESTING_ACQUIRES; - the_mutex_attr.only_owner_release = false; - - if ( the_mutex_attr.discipline == CORE_MUTEX_DISCIPLINES_PRIORITY ) { - if ( _Attributes_Is_inherit_priority( attribute_set ) ) { - the_mutex_attr.discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT; - the_mutex_attr.only_owner_release = true; - } else if ( _Attributes_Is_priority_ceiling( attribute_set ) ) { - the_mutex_attr.discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING; - the_mutex_attr.only_owner_release = true; - } + + if ( _Attributes_Is_inherit_priority( attribute_set ) ) { + the_mutex_attr.discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT; + } else { + _Assert( _Attributes_Is_priority_ceiling( attribute_set ) ); + the_mutex_attr.discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING; } status = _CORE_mutex_Initialize( &the_semaphore->Core_control.mutex, - _Thread_Get_executing(), + executing, &the_mutex_attr, count != 1 ); diff --git a/cpukit/rtems/src/semdelete.c b/cpukit/rtems/src/semdelete.c index da563e5..08eb5db 100644 --- a/cpukit/rtems/src/semdelete.c +++ b/cpukit/rtems/src/semdelete.c @@ -52,6 +52,7 @@ rtems_status_code rtems_semaphore_delete( switch ( the_semaphore->variant ) { case SEMAPHORE_VARIANT_MUTEX: + case SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL: if ( _CORE_mutex_Is_locked( &the_semaphore->Core_control.mutex ) ) { status = STATUS_RESOURCE_IN_USE; } else { @@ -93,6 +94,7 @@ rtems_status_code rtems_semaphore_delete( default: _Assert( the_semaphore->variant == SEMAPHORE_VARIANT_MUTEX + || the_semaphore->variant == SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL || the_semaphore->variant == SEMAPHORE_VARIANT_SIMPLE_BINARY || the_semaphore->variant == SEMAPHORE_VARIANT_COUNTING ); diff --git a/cpukit/rtems/src/semflush.c b/cpukit/rtems/src/semflush.c index 0db8c34..6c1f4dd 100644 --- a/cpukit/rtems/src/semflush.c +++ b/cpukit/rtems/src/semflush.c @@ -58,6 +58,7 @@ rtems_status_code rtems_semaphore_flush( rtems_id id ) default: _Assert( the_semaphore->variant == SEMAPHORE_VARIANT_MUTEX + || the_semaphore->variant == SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL || the_semaphore->variant == SEMAPHORE_VARIANT_SIMPLE_BINARY || the_semaphore->variant == SEMAPHORE_VARIANT_COUNTING ); diff --git a/cpukit/rtems/src/semobtain.c b/cpukit/rtems/src/semobtain.c index b261747..eac6c90 100644 --- a/cpukit/rtems/src/semobtain.c +++ b/cpukit/rtems/src/semobtain.c @@ -30,6 +30,11 @@ THREAD_QUEUE_OBJECT_ASSERT( THREAD_QUEUE_OBJECT_ASSERT( Semaphore_Control, + Core_control.Recursive_mutex.Mutex.Wait_queue +); + +THREAD_QUEUE_OBJECT_ASSERT( + Semaphore_Control, Core_control.mutex.Wait_queue ); @@ -91,6 +96,16 @@ rtems_status_code rtems_semaphore_obtain( &queue_context ); break; + case SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL: + status = _CORE_recursive_mutex_Seize_no_protocol( + &the_semaphore->Core_control.Recursive_mutex, + _Semaphore_Get_operations( the_semaphore ), + executing, + wait, + timeout, + &queue_context + ); + break; default: _Assert( the_semaphore->variant == SEMAPHORE_VARIANT_SIMPLE_BINARY diff --git a/cpukit/rtems/src/semrelease.c b/cpukit/rtems/src/semrelease.c index 3e13334..3e03abd 100644 --- a/cpukit/rtems/src/semrelease.c +++ b/cpukit/rtems/src/semrelease.c @@ -61,6 +61,14 @@ rtems_status_code rtems_semaphore_release( rtems_id id ) &queue_context ); break; + case SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL: + _CORE_recursive_mutex_Surrender_classic_no_protocol( + &the_semaphore->Core_control.Recursive_mutex, + _Semaphore_Get_operations( the_semaphore ), + &queue_context + ); + status = STATUS_SUCCESSFUL; + break; case SEMAPHORE_VARIANT_SIMPLE_BINARY: status = _CORE_semaphore_Surrender( &the_semaphore->Core_control.semaphore, diff --git a/cpukit/score/include/rtems/score/coremutex.h b/cpukit/score/include/rtems/score/coremutex.h index f869409..1c8b6bb 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_mutex; + + /** + * @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 ccc4148..38871dc 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,14 @@ Status_Control _CORE_mutex_Seize_interrupt_blocking( Thread_queue_Context *queue_context ); +Status_Control _CORE_mutex_Seize_blocking( + CORE_mutex_Control *the_mutex, + const Thread_queue_Operations *operations, + Thread_Control *executing, + Watchdog_Interval timeout, + Thread_queue_Context *queue_context +); + /** * @brief Is mutex locked. * @@ -180,10 +190,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 ); @@ -322,7 +329,7 @@ RTEMS_INLINE_ROUTINE void _CORE_mutex_Flush( { _Thread_queue_Flush_critical( &the_mutex->Wait_queue.Queue, - the_mutex->operations, + CORE_MUTEX_TQ_OPERATIONS, filter, queue_context ); @@ -336,22 +343,222 @@ RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_owner( return the_mutex->holder == 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 Status_Control _CORE_mutex_Seize_no_protocol( + CORE_mutex_Control *the_mutex, + const Thread_queue_Operations *operations, + Thread_Control *executing, + bool wait, + Watchdog_Interval timeout, + Thread_queue_Context *queue_context +) +{ + Thread_Control *owner; + + _CORE_mutex_Acquire_critical( the_mutex, queue_context ); + + owner = the_mutex->holder; + + if ( owner == NULL ) { + the_mutex->holder = executing; + _CORE_mutex_Release( the_mutex, queue_context ); + return STATUS_SUCCESSFUL; + } + + if ( owner == executing ) { + _CORE_mutex_Release( the_mutex, queue_context ); + return STATUS_NESTING_NOT_ALLOWED; + } + + if ( !wait ) { + _CORE_mutex_Release( the_mutex, queue_context ); + return STATUS_UNAVAILABLE; + } + + return _CORE_mutex_Seize_blocking( + the_mutex, + operations, + executing, + timeout, + queue_context + ); +} + +RTEMS_INLINE_ROUTINE Status_Control _CORE_mutex_Surrender_no_protocol( + CORE_mutex_Control *the_mutex, + const Thread_queue_Operations *operations, + Thread_Control *executing, + Thread_queue_Context *queue_context +) +{ + Thread_Control *new_owner; + + _CORE_mutex_Acquire_critical( the_mutex, queue_context ); + + if ( executing != the_mutex->holder ) { + _CORE_mutex_Release( the_mutex, queue_context ); + return STATUS_NOT_OWNER; + } + + new_owner = _Thread_queue_First_locked( &the_mutex->Wait_queue, operations ); + the_mutex->holder = new_owner; + + if ( new_owner == NULL ) { + _CORE_mutex_Release( the_mutex, queue_context ); + return STATUS_SUCCESSFUL; + } + + _Thread_queue_Extract_critical( + &the_mutex->Wait_queue.Queue, + operations, + new_owner, + queue_context + ); + return STATUS_SUCCESSFUL; +} + +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 void _CORE_recursive_mutex_Set_owner( + CORE_recursive_mutex_Control *the_mutex, + Thread_Control *owner +) +{ + the_mutex->Mutex.holder = owner; +} + +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, + Thread_queue_Context *queue_context +) +{ + Thread_Control *owner; + + _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context ); + + owner = the_mutex->Mutex.holder; + + if ( owner == NULL ) { + the_mutex->Mutex.holder = executing; + _CORE_mutex_Release( &the_mutex->Mutex, queue_context ); + return STATUS_SUCCESSFUL; + } + + if ( owner == executing ) { + ++the_mutex->nest_level; + _CORE_mutex_Release( &the_mutex->Mutex, queue_context ); + return STATUS_SUCCESSFUL; + } + + if ( !wait ) { + _CORE_mutex_Release( &the_mutex->Mutex, queue_context ); + return STATUS_UNAVAILABLE; + } + + return _CORE_mutex_Seize_blocking( + &the_mutex->Mutex, + operations, + executing, + timeout, + 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 +) +{ + unsigned int nest_level; + Thread_Control *new_owner; + + _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context ); + + if ( executing != the_mutex->Mutex.holder ) { + _CORE_mutex_Release( &the_mutex->Mutex, queue_context ); + return STATUS_NOT_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 STATUS_SUCCESSFUL; + } + + new_owner = _Thread_queue_First_locked( + &the_mutex->Mutex.Wait_queue, + operations + ); + the_mutex->Mutex.holder = new_owner; + + if ( new_owner == NULL ) { + _CORE_mutex_Release( &the_mutex->Mutex, queue_context ); + return STATUS_SUCCESSFUL; + } + + _Thread_queue_Extract_critical( + &the_mutex->Mutex.Wait_queue.Queue, + operations, + new_owner, + 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_classic_no_protocol( + CORE_recursive_mutex_Control *the_mutex, + const Thread_queue_Operations *operations, + Thread_queue_Context *queue_context ) { - return the_attribute->discipline == CORE_MUTEX_DISCIPLINES_FIFO; + unsigned int nest_level; + Thread_Control *new_owner; + + _CORE_mutex_Acquire_critical( &the_mutex->Mutex, queue_context ); + + 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 + ); + the_mutex->Mutex.holder = 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 + ); } /** @} */ diff --git a/cpukit/score/src/apimutex.c b/cpukit/score/src/apimutex.c index a098edb..8af374a 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 ec073ff..6f73c1b 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 37de3a1..dfee1d3 100644 --- a/cpukit/score/src/coremutexseize.c +++ b/cpukit/score/src/coremutexseize.c @@ -71,7 +71,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, @@ -85,3 +85,22 @@ Status_Control _CORE_mutex_Seize_interrupt_blocking( return _Thread_Wait_get_status( executing ); } +Status_Control _CORE_mutex_Seize_blocking( + CORE_mutex_Control *the_mutex, + const Thread_queue_Operations *operations, + Thread_Control *executing, + Watchdog_Interval timeout, + Thread_queue_Context *queue_context +) +{ + _Thread_queue_Context_set_expected_level( queue_context, 0 ); + _Thread_queue_Enqueue_critical( + &the_mutex->Wait_queue.Queue, + operations, + executing, + STATES_WAITING_FOR_MUTEX, + timeout, + queue_context + ); + return _Thread_Wait_get_status( executing ); +} diff --git a/cpukit/score/src/coremutexsurrender.c b/cpukit/score/src/coremutexsurrender.c index 6047409..2d976e0 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 ); -- 1.8.4.5 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel