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/libmisc/monitor/mon-sema.c | 5 +- cpukit/libnetworking/rtems/rtems_glue.c | 6 +- cpukit/posix/include/rtems/posix/mutex.h | 33 ++++- cpukit/posix/include/rtems/posix/muteximpl.h | 35 +++++ cpukit/posix/src/mutexdestroy.c | 12 +- cpukit/posix/src/mutexgetprioceiling.c | 6 +- cpukit/posix/src/mutexinit.c | 63 +++++--- cpukit/posix/src/mutexlocksupp.c | 59 ++++++-- cpukit/posix/src/mutexsetprioceiling.c | 5 +- cpukit/posix/src/mutexunlock.c | 21 ++- cpukit/rtems/include/rtems/rtems/sem.h | 2 +- cpukit/rtems/include/rtems/rtems/semimpl.h | 6 + cpukit/rtems/src/semcreate.c | 59 ++++---- cpukit/rtems/src/semdelete.c | 8 +- cpukit/rtems/src/semflush.c | 1 + cpukit/rtems/src/semobtain.c | 15 +- cpukit/rtems/src/semrelease.c | 10 +- cpukit/rtems/src/semsetpriority.c | 3 +- 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 +--- 24 files changed, 510 insertions(+), 172 deletions(-) diff --git a/cpukit/libmisc/monitor/mon-sema.c b/cpukit/libmisc/monitor/mon-sema.c index 5add7cf06f..bc745294e7 100644 --- a/cpukit/libmisc/monitor/mon-sema.c +++ b/cpukit/libmisc/monitor/mon-sema.c @@ -22,7 +22,7 @@ rtems_monitor_sema_canonical( canonical_sema->attribute = rtems_sema->attribute_set; canonical_sema->priority_ceiling = - rtems_sema->Core_control.mutex.Attributes.priority_ceiling; + rtems_sema->Core_control.Mutex.priority_ceiling; canonical_sema->holder_id = 0; @@ -33,8 +33,9 @@ rtems_monitor_sema_canonical( } else { /* we have a binary semaphore (mutex) */ - Thread_Control *holder = rtems_sema->Core_control.mutex.holder; + Thread_Control *holder; + holder = rtems_sema->Core_control.Mutex.Recursive.Mutex.holder; if (holder != NULL) { canonical_sema->holder_id = holder->Object.id; canonical_sema->cur_count = 0; diff --git a/cpukit/libnetworking/rtems/rtems_glue.c b/cpukit/libnetworking/rtems/rtems_glue.c index 9b6338c5e3..45bb4d2231 100644 --- a/cpukit/libnetworking/rtems/rtems_glue.c +++ b/cpukit/libnetworking/rtems/rtems_glue.c @@ -118,7 +118,7 @@ rtems_bsdnet_semaphore_release_recursive(void) nest_count = the_networkSemaphore ? - the_networkSemaphore->Core_control.mutex.nest_count : 0; + the_networkSemaphore->Core_control.Mutex.Recursive.Mutex.nest_count : 0; for (i = 0; i < nest_count; ++i) { rtems_bsdnet_semaphore_release(); } @@ -378,7 +378,7 @@ rtems_bsdnet_semaphore_obtain (void) _Thread_queue_Context_initialize(&queue_context); _ISR_lock_ISR_disable(&queue_context.Lock_context); status = _CORE_mutex_Seize ( - &the_networkSemaphore->Core_control.mutex, + &the_networkSemaphore->Core_control.Mutex.Recursive.Mutex, _Thread_Executing, 1, /* wait */ 0, /* forever */ @@ -411,7 +411,7 @@ rtems_bsdnet_semaphore_release (void) _Thread_queue_Context_initialize(&queue_context); _ISR_lock_ISR_disable(&queue_context.Lock_context); status = _CORE_mutex_Surrender ( - &the_networkSemaphore->Core_control.mutex, + &the_networkSemaphore->Core_control.Mutex.Recursive.Mutex, &queue_context ); if (status != STATUS_SUCCESSFUL) diff --git a/cpukit/posix/include/rtems/posix/mutex.h b/cpukit/posix/include/rtems/posix/mutex.h index e1dfa34e8c..97ab138652 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 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 30cc19da7e..4957e207fb 100644 --- a/cpukit/posix/include/rtems/posix/muteximpl.h +++ b/cpukit/posix/include/rtems/posix/muteximpl.h @@ -28,6 +28,19 @@ extern "C" { #endif +#define POSIX_MUTEX_NO_PROTOCOL_TQ_OPERATIONS &_Thread_queue_Operations_FIFO + +/** + * @brief Supported POSIX mutex protocols. + * + * Must be in synchronization with POSIX_Mutex_Control::protocol. + */ +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 +52,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->Mutex.Recursive.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->Mutex.Recursive.Mutex, + queue_context + ); +} + /** * @brief POSIX Mutex Allocate * diff --git a/cpukit/posix/src/mutexdestroy.c b/cpukit/posix/src/mutexdestroy.c index 7fda7d3ac9..57e63937a9 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->Mutex.Recursive.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->Mutex.Recursive.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 268457a73e..06eaf30764 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->Mutex.Recursive.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 d90b391c9d..f2912ead18 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->Mutex.Recursive + ); + } 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->Mutex.Recursive.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 6ecf87cb46..2499ae1ace 100644 --- a/cpukit/posix/src/mutexlocksupp.c +++ b/cpukit/posix/src/mutexlocksupp.c @@ -21,16 +21,39 @@ #include #include -THREAD_QUEUE_OBJECT_ASSERT( POSIX_Mutex_Control, Mutex.Wait_queue ); +THREAD_QUEUE_OBJECT_ASSERT( + POSIX_Mutex_Control, + Mutex.Recursive.Mutex.Wait_queue +); + +static Status_Control _POSIX_Mutex_Lock_nested( + CORE_recursive_mutex_Control *the_recursive_mutex +) +{ + POSIX_Mutex_Control *the_mutex; + + the_mutex = RTEMS_CONTAINER_OF( + the_recursive_mutex, + POSIX_Mutex_Control, + Mutex.Recursive + ); + + if ( the_mutex->is_recursive ) { + return _CORE_recursive_mutex_Seize_nested( the_recursive_mutex ); + } else { + return STATUS_NESTING_NOT_ALLOWED; + } +} int _POSIX_Mutex_Lock_support( pthread_mutex_t *mutex, - bool blocking, + bool wait, Watchdog_Interval timeout ) { 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 +62,30 @@ 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: + status = _CORE_recursive_mutex_Seize_no_protocol( + &the_mutex->Mutex.Recursive, + POSIX_MUTEX_NO_PROTOCOL_TQ_OPERATIONS, + executing, + wait, + timeout, + _POSIX_Mutex_Lock_nested, + &queue_context + ); + break; + default: + status = _CORE_mutex_Seize( + &the_mutex->Mutex.Recursive.Mutex, + executing, + wait, + timeout, + &queue_context + ); + break; + } + return _POSIX_Get_error( status ); } diff --git a/cpukit/posix/src/mutexsetprioceiling.c b/cpukit/posix/src/mutexsetprioceiling.c index 20f14dc1f6..5d11edf294 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->Mutex.Recursive.Mutex.Attributes.priority_ceiling ); - the_mutex->Mutex.Attributes.priority_ceiling = the_priority; + the_mutex->Mutex.Recursive.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 1c3f2d83f4..b0ca33d154 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,24 @@ 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: + status = _CORE_recursive_mutex_Surrender_no_protocol( + &the_mutex->Mutex.Recursive, + POSIX_MUTEX_NO_PROTOCOL_TQ_OPERATIONS, + executing, + &queue_context + ); + break; + default: + status = _CORE_mutex_Surrender( + &the_mutex->Mutex.Recursive.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 fe74f44dfa..220b0e392e 100644 --- a/cpukit/rtems/include/rtems/rtems/sem.h +++ b/cpukit/rtems/include/rtems/rtems/sem.h @@ -83,7 +83,7 @@ typedef struct { * This is the SuperCore Mutex instance associated with this Classic * API Semaphore instance. */ - CORE_mutex_Control mutex; + CORE_ceiling_mutex_Control Mutex; /** * This is the SuperCore Semaphore instance associated with this Classic diff --git a/cpukit/rtems/include/rtems/rtems/semimpl.h b/cpukit/rtems/include/rtems/rtems/semimpl.h index f3dfa0213a..5b789d627d 100644 --- a/cpukit/rtems/include/rtems/rtems/semimpl.h +++ b/cpukit/rtems/include/rtems/rtems/semimpl.h @@ -26,8 +26,14 @@ extern "C" { #endif +/** + * @brief Classic semaphore variants. + * + * Must be in synchronization with Semaphore_Control::variant. + */ 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 455182bd90..91f693c6c0 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.Mutex.Recursive + ); + + if ( count == 0 ) { + _CORE_mutex_Set_owner( + &the_semaphore->Core_control.Mutex.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(), + &the_semaphore->Core_control.Mutex.Recursive.Mutex, + executing, &the_mutex_attr, count != 1 ); diff --git a/cpukit/rtems/src/semdelete.c b/cpukit/rtems/src/semdelete.c index 34da496b8d..365d895362 100644 --- a/cpukit/rtems/src/semdelete.c +++ b/cpukit/rtems/src/semdelete.c @@ -51,7 +51,12 @@ rtems_status_code rtems_semaphore_delete( switch ( the_semaphore->variant ) { case SEMAPHORE_VARIANT_MUTEX: - if ( _CORE_mutex_Is_locked( &the_semaphore->Core_control.mutex ) ) { + case SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL: + if ( + _CORE_mutex_Is_locked( + &the_semaphore->Core_control.Mutex.Recursive.Mutex + ) + ) { status = STATUS_RESOURCE_IN_USE; } else { status = STATUS_SUCCESSFUL; @@ -92,6 +97,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 0db8c34dfb..6c1f4ddf2c 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 5eebfa14b2..a7774d6f91 100644 --- a/cpukit/rtems/src/semobtain.c +++ b/cpukit/rtems/src/semobtain.c @@ -29,7 +29,7 @@ THREAD_QUEUE_OBJECT_ASSERT( THREAD_QUEUE_OBJECT_ASSERT( Semaphore_Control, - Core_control.mutex.Wait_queue + Core_control.Mutex.Recursive.Mutex.Wait_queue ); THREAD_QUEUE_OBJECT_ASSERT( @@ -83,13 +83,24 @@ rtems_status_code rtems_semaphore_obtain( #endif case SEMAPHORE_VARIANT_MUTEX: status = _CORE_mutex_Seize( - &the_semaphore->Core_control.mutex, + &the_semaphore->Core_control.Mutex.Recursive.Mutex, executing, wait, timeout, &queue_context ); break; + case SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL: + status = _CORE_recursive_mutex_Seize_no_protocol( + &the_semaphore->Core_control.Mutex.Recursive, + _Semaphore_Get_operations( the_semaphore ), + executing, + wait, + timeout, + _CORE_recursive_mutex_Seize_nested, + &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 3e13334e87..7cd92cfe0d 100644 --- a/cpukit/rtems/src/semrelease.c +++ b/cpukit/rtems/src/semrelease.c @@ -57,10 +57,18 @@ rtems_status_code rtems_semaphore_release( rtems_id id ) #endif case SEMAPHORE_VARIANT_MUTEX: status = _CORE_mutex_Surrender( - &the_semaphore->Core_control.mutex, + &the_semaphore->Core_control.Mutex.Recursive.Mutex, &queue_context ); break; + case SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL: + _CORE_recursive_mutex_Surrender_no_protocol_classic( + &the_semaphore->Core_control.Mutex.Recursive, + _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/rtems/src/semsetpriority.c b/cpukit/rtems/src/semsetpriority.c index ee6614af0f..0a8c58cde2 100644 --- a/cpukit/rtems/src/semsetpriority.c +++ b/cpukit/rtems/src/semsetpriority.c @@ -54,8 +54,9 @@ static rtems_status_code _Semaphore_Set_priority( } else #endif if ( _Attributes_Is_priority_ceiling( attribute_set ) ) { - CORE_mutex_Control *mutex = &the_semaphore->Core_control.mutex; + CORE_mutex_Control *mutex; + mutex = &the_semaphore->Core_control.Mutex.Recursive.Mutex; _CORE_mutex_Acquire_critical( mutex, queue_context ); old_priority = mutex->Attributes.priority_ceiling; 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