From 0b713f8940d90b480f8cd36663c11aa0688587d8 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 30 May 2016 06:59:55 +0200 Subject: score: Rework CORE inherit priority mutex Provide dedicated seize and surrender methods for inherit priority mutexes. This eliminates CORE_mutex_Attributes. --- cpukit/libmisc/monitor/mon-sema.c | 94 ++++++-- cpukit/libnetworking/rtems/rtems_glue.c | 20 +- cpukit/posix/src/mutexinit.c | 43 ++-- cpukit/posix/src/mutexlocksupp.c | 5 +- cpukit/posix/src/mutexunlock.c | 5 +- cpukit/rtems/include/rtems/rtems/sem.h | 7 - cpukit/rtems/include/rtems/rtems/semimpl.h | 2 +- cpukit/rtems/src/semcreate.c | 35 ++- cpukit/rtems/src/semdelete.c | 4 +- cpukit/rtems/src/semflush.c | 2 +- cpukit/rtems/src/semobtain.c | 7 +- cpukit/rtems/src/semrelease.c | 7 +- cpukit/rtems/src/semsetpriority.c | 2 +- cpukit/score/Makefile.am | 4 +- cpukit/score/include/rtems/score/apimutex.h | 2 +- cpukit/score/include/rtems/score/coremutex.h | 49 ----- cpukit/score/include/rtems/score/coremuteximpl.h | 263 ++++++++++------------- cpukit/score/src/apimutex.c | 6 +- cpukit/score/src/apimutexisowner.c | 6 +- cpukit/score/src/apimutexlock.c | 7 +- cpukit/score/src/apimutexunlock.c | 8 +- cpukit/score/src/coremutex.c | 53 ----- cpukit/score/src/coremutexseize.c | 17 +- cpukit/score/src/coremutexsurrender.c | 127 ++--------- cpukit/score/src/debugisownerofallocator.c | 2 +- 25 files changed, 292 insertions(+), 485 deletions(-) delete mode 100644 cpukit/score/src/coremutex.c diff --git a/cpukit/libmisc/monitor/mon-sema.c b/cpukit/libmisc/monitor/mon-sema.c index bc745294e7..d7a7aafc9c 100644 --- a/cpukit/libmisc/monitor/mon-sema.c +++ b/cpukit/libmisc/monitor/mon-sema.c @@ -8,7 +8,7 @@ #include #include "monitor.h" -#include +#include #include #include /* memcpy() */ @@ -19,31 +19,81 @@ rtems_monitor_sema_canonical( ) { const Semaphore_Control *rtems_sema = (const Semaphore_Control *) sema_void; + Thread_Control *owner; - canonical_sema->attribute = rtems_sema->attribute_set; - canonical_sema->priority_ceiling = - rtems_sema->Core_control.Mutex.priority_ceiling; + memset(canonical_sema, 0, sizeof(*canonical_sema)); - canonical_sema->holder_id = 0; +#if defined(RTEMS_MULTIPROCESSING) + if (rtems_sema->is_global) { + canonical_sema->attribute |= RTEMS_GLOBAL; + } +#endif - if (_Attributes_Is_counting_semaphore(canonical_sema->attribute)) { - /* we have a counting semaphore */ - canonical_sema->cur_count = rtems_sema->Core_control.semaphore.count; - canonical_sema->max_count = UINT32_MAX; + if (rtems_sema->discipline == SEMAPHORE_DISCIPLINE_PRIORITY) { + canonical_sema->attribute |= RTEMS_PRIORITY; + } + + switch ( rtems_sema->variant ) { + case SEMAPHORE_VARIANT_MUTEX_INHERIT_PRIORITY: + canonical_sema->attribute |= RTEMS_BINARY_SEMAPHORE + | RTEMS_INHERIT_PRIORITY; + break; + case SEMAPHORE_VARIANT_MUTEX_PRIORITY_CEILING: + canonical_sema->attribute |= RTEMS_BINARY_SEMAPHORE + | RTEMS_PRIORITY_CEILING; + break; + case SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL: + canonical_sema->attribute |= RTEMS_BINARY_SEMAPHORE; + break; +#if defined(RTEMS_SMP) + case SEMAPHORE_VARIANT_MRSP: + canonical_sema->attribute |= RTEMS_BINARY_SEMAPHORE + | RTEMS_MULTIPROCESSOR_RESOURCE_SHARING; + break; +#endif + case SEMAPHORE_VARIANT_SIMPLE_BINARY: + canonical_sema->attribute |= RTEMS_SIMPLE_BINARY_SEMAPHORE; + break; + case SEMAPHORE_VARIANT_COUNTING: + canonical_sema->attribute |= RTEMS_COUNTING_SEMAPHORE; + break; } - else { - /* we have a binary semaphore (mutex) */ - 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; - } else { - canonical_sema->cur_count = 1; - } - - canonical_sema->max_count = 1; /* mutex is either 0 or 1 */ + + switch ( rtems_sema->variant ) { + case SEMAPHORE_VARIANT_MUTEX_PRIORITY_CEILING: + canonical_sema->priority_ceiling = + rtems_sema->Core_control.Mutex.priority_ceiling; + /* Fall through */ + case SEMAPHORE_VARIANT_MUTEX_INHERIT_PRIORITY: + case SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL: + owner = _CORE_mutex_Get_owner( + &rtems_sema->Core_control.Mutex.Recursive.Mutex + ); + + if (owner != NULL) { + canonical_sema->holder_id = owner->Object.id; + canonical_sema->cur_count = 0; + } else { + canonical_sema->cur_count = 1; + } + + canonical_sema->max_count = 1; + break; +#if defined(RTEMS_SMP) + case SEMAPHORE_VARIANT_MRSP: + canonical_sema->cur_count = + rtems_sema->Core_control.mrsp.Resource.owner == NULL; + canonical_sema->max_count = 1; + break; +#endif + case SEMAPHORE_VARIANT_SIMPLE_BINARY: + canonical_sema->cur_count = rtems_sema->Core_control.semaphore.count; + canonical_sema->max_count = 1; + break; + case SEMAPHORE_VARIANT_COUNTING: + canonical_sema->cur_count = rtems_sema->Core_control.semaphore.count; + canonical_sema->max_count = UINT32_MAX; + break; } } diff --git a/cpukit/libnetworking/rtems/rtems_glue.c b/cpukit/libnetworking/rtems/rtems_glue.c index 45bb4d2231..e9b371f700 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.Recursive.Mutex.nest_count : 0; + the_networkSemaphore->Core_control.Mutex.Recursive.nest_level + 1 : 0; for (i = 0; i < nest_count; ++i) { rtems_bsdnet_semaphore_release(); } @@ -377,13 +377,14 @@ rtems_bsdnet_semaphore_obtain (void) rtems_panic ("rtems-net: network sema obtain: network not initialised\n"); _Thread_queue_Context_initialize(&queue_context); _ISR_lock_ISR_disable(&queue_context.Lock_context); - status = _CORE_mutex_Seize ( - &the_networkSemaphore->Core_control.Mutex.Recursive.Mutex, + status = _CORE_recursive_mutex_Seize ( + &the_networkSemaphore->Core_control.Mutex.Recursive, _Thread_Executing, - 1, /* wait */ - 0, /* forever */ + true, /* wait */ + WATCHDOG_NO_TIMEOUT, /* forever */ + _CORE_recursive_mutex_Seize_nested, &queue_context - ); + ); if (status != STATUS_SUCCESSFUL) rtems_panic ("rtems-net: can't obtain network sema: %d\n", status); #else @@ -410,10 +411,11 @@ rtems_bsdnet_semaphore_release (void) rtems_panic ("rtems-net: network sema obtain: network not initialised\n"); _Thread_queue_Context_initialize(&queue_context); _ISR_lock_ISR_disable(&queue_context.Lock_context); - status = _CORE_mutex_Surrender ( - &the_networkSemaphore->Core_control.Mutex.Recursive.Mutex, + status = _CORE_recursive_mutex_Surrender( + &the_networkSemaphore->Core_control.Mutex.Recursive, + _Thread_Executing, &queue_context - ); + ); if (status != STATUS_SUCCESSFUL) rtems_panic ("rtems-net: can't release network sema: %i\n"); #else diff --git a/cpukit/posix/src/mutexinit.c b/cpukit/posix/src/mutexinit.c index 6c5705b20b..73f0544965 100644 --- a/cpukit/posix/src/mutexinit.c +++ b/cpukit/posix/src/mutexinit.c @@ -119,33 +119,22 @@ int pthread_mutex_init( the_mutex->protocol = protocol; the_mutex->is_recursive = ( the_attr->type == PTHREAD_MUTEX_RECURSIVE ); - if ( protocol == POSIX_MUTEX_PRIORITY_CEILING ) { - _CORE_ceiling_mutex_Initialize( - &the_mutex->Mutex, - _POSIX_Priority_To_core( the_attr->prio_ceiling ) - ); - } else 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; - } - - /* - * Must be initialized to unlocked. - */ - _CORE_mutex_Initialize( - &the_mutex->Mutex.Recursive.Mutex, - NULL, - &the_mutex_attr, - false - ); + switch ( the_mutex->protocol ) { + case POSIX_MUTEX_PRIORITY_CEILING: + _CORE_ceiling_mutex_Initialize( + &the_mutex->Mutex, + _POSIX_Priority_To_core( the_attr->prio_ceiling ) + ); + break; + default: + _Assert( + the_mutex->protocol == POSIX_MUTEX_NO_PROTOCOL + || the_mutex->protocol == POSIX_MUTEX_PRIORITY_INHERIT + ); + _CORE_recursive_mutex_Initialize( + &the_mutex->Mutex.Recursive + ); + break; } _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 cccb2d31b3..d3d07f68e8 100644 --- a/cpukit/posix/src/mutexlocksupp.c +++ b/cpukit/posix/src/mutexlocksupp.c @@ -88,11 +88,12 @@ int _POSIX_Mutex_Lock_support( break; default: _Assert( the_mutex->protocol == POSIX_MUTEX_PRIORITY_INHERIT ); - status = _CORE_mutex_Seize( - &the_mutex->Mutex.Recursive.Mutex, + status = _CORE_recursive_mutex_Seize( + &the_mutex->Mutex.Recursive, executing, wait, timeout, + _POSIX_Mutex_Lock_nested, &queue_context ); break; diff --git a/cpukit/posix/src/mutexunlock.c b/cpukit/posix/src/mutexunlock.c index 5404cef187..3144314e5c 100644 --- a/cpukit/posix/src/mutexunlock.c +++ b/cpukit/posix/src/mutexunlock.c @@ -62,8 +62,9 @@ int pthread_mutex_unlock( break; default: _Assert( the_mutex->protocol == POSIX_MUTEX_PRIORITY_INHERIT ); - status = _CORE_mutex_Surrender( - &the_mutex->Mutex.Recursive.Mutex, + status = _CORE_recursive_mutex_Surrender( + &the_mutex->Mutex.Recursive, + executing, &queue_context ); break; diff --git a/cpukit/rtems/include/rtems/rtems/sem.h b/cpukit/rtems/include/rtems/rtems/sem.h index 220b0e392e..725d9999e5 100644 --- a/cpukit/rtems/include/rtems/rtems/sem.h +++ b/cpukit/rtems/include/rtems/rtems/sem.h @@ -113,13 +113,6 @@ typedef struct { #if defined(RTEMS_MULTIPROCESSING) unsigned int is_global : 1; #endif - - /** - * This is the Classic API attribute provided to the create directive. - * It is translated into behavioral attributes on the SuperCore Semaphore - * or Mutex instance. - */ - rtems_attribute attribute_set; } Semaphore_Control; /** diff --git a/cpukit/rtems/include/rtems/rtems/semimpl.h b/cpukit/rtems/include/rtems/rtems/semimpl.h index 9d82a12b3c..3259916d52 100644 --- a/cpukit/rtems/include/rtems/rtems/semimpl.h +++ b/cpukit/rtems/include/rtems/rtems/semimpl.h @@ -32,7 +32,7 @@ extern "C" { * Must be in synchronization with Semaphore_Control::variant. */ typedef enum { - SEMAPHORE_VARIANT_MUTEX, + SEMAPHORE_VARIANT_MUTEX_INHERIT_PRIORITY, SEMAPHORE_VARIANT_MUTEX_PRIORITY_CEILING, SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL, SEMAPHORE_VARIANT_SIMPLE_BINARY, diff --git a/cpukit/rtems/src/semcreate.c b/cpukit/rtems/src/semcreate.c index 720fb63a0d..943d787246 100644 --- a/cpukit/rtems/src/semcreate.c +++ b/cpukit/rtems/src/semcreate.c @@ -61,10 +61,9 @@ rtems_status_code rtems_semaphore_create( rtems_id *id ) { - Semaphore_Control *the_semaphore; - CORE_mutex_Attributes the_mutex_attr; - Thread_Control *executing; - Status_Control status; + Semaphore_Control *the_semaphore; + Thread_Control *executing; + Status_Control status; if ( !rtems_is_name_valid( name ) ) return RTEMS_INVALID_NAME; @@ -137,7 +136,6 @@ rtems_status_code rtems_semaphore_create( #endif priority_ceiling = _RTEMS_tasks_Priority_to_Core( priority_ceiling ); - the_semaphore->attribute_set = attribute_set; executing = _Thread_Get_executing(); if ( _Attributes_Is_priority( attribute_set ) ) { @@ -195,9 +193,15 @@ rtems_status_code rtems_semaphore_create( } else { status = STATUS_SUCCESSFUL; } - } else if ( !_Attributes_Is_inherit_priority( attribute_set ) ) { + } else { _Assert( _Attributes_Is_binary_semaphore( attribute_set ) ); - the_semaphore->variant = SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL; + + if ( _Attributes_Is_inherit_priority( attribute_set ) ) { + the_semaphore->variant = SEMAPHORE_VARIANT_MUTEX_INHERIT_PRIORITY; + } else { + the_semaphore->variant = SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL; + } + _CORE_recursive_mutex_Initialize( &the_semaphore->Core_control.Mutex.Recursive ); @@ -207,22 +211,13 @@ rtems_status_code rtems_semaphore_create( &the_semaphore->Core_control.Mutex.Recursive.Mutex, executing ); + + if ( _Attributes_Is_inherit_priority( attribute_set ) ) { + ++executing->resource_count; + } } status = STATUS_SUCCESSFUL; - } else { - _Assert( _Attributes_Is_binary_semaphore( attribute_set ) ); - _Assert( _Attributes_Is_inherit_priority( attribute_set ) ); - the_semaphore->variant = SEMAPHORE_VARIANT_MUTEX; - - the_mutex_attr.lock_nesting_behavior = CORE_MUTEX_NESTING_ACQUIRES; - - status = _CORE_mutex_Initialize( - &the_semaphore->Core_control.Mutex.Recursive.Mutex, - executing, - &the_mutex_attr, - count != 1 - ); } if ( status != STATUS_SUCCESSFUL ) { diff --git a/cpukit/rtems/src/semdelete.c b/cpukit/rtems/src/semdelete.c index a38d761320..db8c8008e5 100644 --- a/cpukit/rtems/src/semdelete.c +++ b/cpukit/rtems/src/semdelete.c @@ -50,7 +50,7 @@ rtems_status_code rtems_semaphore_delete( ); switch ( the_semaphore->variant ) { - case SEMAPHORE_VARIANT_MUTEX: + case SEMAPHORE_VARIANT_MUTEX_INHERIT_PRIORITY: case SEMAPHORE_VARIANT_MUTEX_PRIORITY_CEILING: case SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL: if ( @@ -97,7 +97,7 @@ rtems_status_code rtems_semaphore_delete( #endif default: _Assert( - the_semaphore->variant == SEMAPHORE_VARIANT_MUTEX + the_semaphore->variant == SEMAPHORE_VARIANT_MUTEX_INHERIT_PRIORITY || the_semaphore->variant == SEMAPHORE_VARIANT_MUTEX_PRIORITY_CEILING || the_semaphore->variant == SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL || the_semaphore->variant == SEMAPHORE_VARIANT_SIMPLE_BINARY diff --git a/cpukit/rtems/src/semflush.c b/cpukit/rtems/src/semflush.c index 17c589f588..3970d22fc7 100644 --- a/cpukit/rtems/src/semflush.c +++ b/cpukit/rtems/src/semflush.c @@ -57,7 +57,7 @@ rtems_status_code rtems_semaphore_flush( rtems_id id ) #endif default: _Assert( - the_semaphore->variant == SEMAPHORE_VARIANT_MUTEX + the_semaphore->variant == SEMAPHORE_VARIANT_MUTEX_INHERIT_PRIORITY || the_semaphore->variant == SEMAPHORE_VARIANT_MUTEX_PRIORITY_CEILING || the_semaphore->variant == SEMAPHORE_VARIANT_MUTEX_NO_PROTOCOL || the_semaphore->variant == SEMAPHORE_VARIANT_SIMPLE_BINARY diff --git a/cpukit/rtems/src/semobtain.c b/cpukit/rtems/src/semobtain.c index 44507abefb..80bb199dc2 100644 --- a/cpukit/rtems/src/semobtain.c +++ b/cpukit/rtems/src/semobtain.c @@ -81,12 +81,13 @@ rtems_status_code rtems_semaphore_obtain( ); break; #endif - case SEMAPHORE_VARIANT_MUTEX: - status = _CORE_mutex_Seize( - &the_semaphore->Core_control.Mutex.Recursive.Mutex, + case SEMAPHORE_VARIANT_MUTEX_INHERIT_PRIORITY: + status = _CORE_recursive_mutex_Seize( + &the_semaphore->Core_control.Mutex.Recursive, executing, wait, timeout, + _CORE_recursive_mutex_Seize_nested, &queue_context ); break; diff --git a/cpukit/rtems/src/semrelease.c b/cpukit/rtems/src/semrelease.c index d92197b8f4..0808a2a475 100644 --- a/cpukit/rtems/src/semrelease.c +++ b/cpukit/rtems/src/semrelease.c @@ -58,9 +58,10 @@ rtems_status_code rtems_semaphore_release( rtems_id id ) ); break; #endif - case SEMAPHORE_VARIANT_MUTEX: - status = _CORE_mutex_Surrender( - &the_semaphore->Core_control.Mutex.Recursive.Mutex, + case SEMAPHORE_VARIANT_MUTEX_INHERIT_PRIORITY: + status = _CORE_recursive_mutex_Surrender( + &the_semaphore->Core_control.Mutex.Recursive, + executing, &queue_context ); break; diff --git a/cpukit/rtems/src/semsetpriority.c b/cpukit/rtems/src/semsetpriority.c index 57a5368353..14aa34eae4 100644 --- a/cpukit/rtems/src/semsetpriority.c +++ b/cpukit/rtems/src/semsetpriority.c @@ -75,7 +75,7 @@ static rtems_status_code _Semaphore_Set_priority( #endif default: _Assert( - the_semaphore->variant == SEMAPHORE_VARIANT_MUTEX + the_semaphore->variant == SEMAPHORE_VARIANT_MUTEX_INHERIT_PRIORITY || 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/score/Makefile.am b/cpukit/score/Makefile.am index fae6fc37bb..29e822d47d 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -181,8 +181,8 @@ libscore_a_SOURCES += src/coremsg.c src/coremsgbroadcast.c \ src/coremsgsubmit.c ## CORE_MUTEX_C_FILES -libscore_a_SOURCES += src/coremutex.c \ - src/coremutexseize.c src/coremutexsurrender.c +libscore_a_SOURCES += src/coremutexseize.c +libscore_a_SOURCES += src/coremutexsurrender.c ## CORE_PERCPU_C_FILES libscore_a_SOURCES += src/percpu.c diff --git a/cpukit/score/include/rtems/score/apimutex.h b/cpukit/score/include/rtems/score/apimutex.h index 1a4b1ee445..aa08481c83 100644 --- a/cpukit/score/include/rtems/score/apimutex.h +++ b/cpukit/score/include/rtems/score/apimutex.h @@ -46,7 +46,7 @@ typedef struct { /** * Contains the SuperCore mutex information. */ - CORE_mutex_Control Mutex; + CORE_recursive_mutex_Control Mutex; /** * @brief The thread life protection state before the outer-most mutex diff --git a/cpukit/score/include/rtems/score/coremutex.h b/cpukit/score/include/rtems/score/coremutex.h index 704ea0da24..2bde8b5ebd 100644 --- a/cpukit/score/include/rtems/score/coremutex.h +++ b/cpukit/score/include/rtems/score/coremutex.h @@ -41,47 +41,6 @@ extern "C" { */ /**@{*/ -/** - * @brief The possible behaviors for lock nesting. - * - * This enumerated type defines the possible behaviors for - * lock nesting. - */ -typedef enum { - /** - * This sequence has no blocking or errors: - * - * + lock(m) - * + lock(m) - * + unlock(m) - * + unlock(m) - */ - CORE_MUTEX_NESTING_ACQUIRES, -#if defined(RTEMS_POSIX_API) - /** - * This sequence returns an error at the indicated point: - * - * + lock(m) - * + lock(m) - already locked error - * + unlock(m) - */ - CORE_MUTEX_NESTING_IS_ERROR, -#endif -} CORE_mutex_Nesting_behaviors; - -/** - * @brief The control block used to manage attributes of each mutex. - * - * The following defines the control block used to manage the - * attributes of each mutex. - */ -typedef struct { - /** This field determines what the behavior of this mutex instance will - * be when attempting to acquire the mutex when it is already locked. - */ - CORE_mutex_Nesting_behaviors lock_nesting_behavior; -} CORE_mutex_Attributes; - /** * @brief Control block used to manage each mutex. * @@ -93,14 +52,6 @@ typedef struct { */ Thread_queue_Control Wait_queue; - /** This element is the set of attributes which define this instance's - * behavior. - */ - CORE_mutex_Attributes Attributes; - /** This element contains the number of times the mutex has been acquired - * nested. This must be zero (0) before the mutex is actually unlocked. - */ - uint32_t nest_count; /** This element points to the thread which is currently holding this mutex. * The holder is the last thread to successfully lock the mutex and which * has not unlocked it. If the thread is not locked, there is no holder. diff --git a/cpukit/score/include/rtems/score/coremuteximpl.h b/cpukit/score/include/rtems/score/coremuteximpl.h index f459743346..69311e4101 100644 --- a/cpukit/score/include/rtems/score/coremuteximpl.h +++ b/cpukit/score/include/rtems/score/coremuteximpl.h @@ -35,26 +35,13 @@ extern "C" { #define CORE_MUTEX_TQ_OPERATIONS &_Thread_queue_Operations_priority -/** - * @brief Initializes the mutex based on the parameters passed. - * - * This routine initializes the mutex based on the parameters passed. - * - * @param[in,out] the_mutex is the mutex to initalize - * @param[in,out] executing The currently executing thread. - * @param[in] the_mutex_attributes is the attributes associated with this - * mutex instance - * @param[in] initially_locked If true, then the mutex is initially locked by - * the executing thread. - * - * @retval This method returns STATUS_SUCCESSFUL if successful. - */ -Status_Control _CORE_mutex_Initialize( - CORE_mutex_Control *the_mutex, - Thread_Control *executing, - const CORE_mutex_Attributes *the_mutex_attributes, - bool initially_locked -); +RTEMS_INLINE_ROUTINE void _CORE_mutex_Initialize( + CORE_mutex_Control *the_mutex +) +{ + _Thread_queue_Initialize( &the_mutex->Wait_queue ); + the_mutex->holder = NULL; +} RTEMS_INLINE_ROUTINE void _CORE_mutex_Destroy( CORE_mutex_Control *the_mutex ) { @@ -83,25 +70,6 @@ RTEMS_INLINE_ROUTINE void _CORE_mutex_Release( ); } -/** - * @brief Performs the blocking portion of a mutex obtain. - * - * This routine performs the blocking portion of a mutex obtain. - * It is an actual subroutine and is not implemented as something - * that may be inlined. - * - * @param[in,out] the_mutex is the mutex to attempt to lock - * @param[in,out] executing The currently executing thread. - * @param[in] timeout is the maximum number of ticks to block - * @param[in] lock_context is the interrupt level - */ -Status_Control _CORE_mutex_Seize_interrupt_blocking( - CORE_mutex_Control *the_mutex, - Thread_Control *executing, - Watchdog_Interval timeout, - Thread_queue_Context *queue_context -); - RTEMS_INLINE_ROUTINE Thread_Control *_CORE_mutex_Get_owner( const CORE_mutex_Control *the_mutex ) @@ -127,124 +95,14 @@ RTEMS_INLINE_ROUTINE bool _CORE_mutex_Is_locked( return _CORE_mutex_Get_owner( the_mutex ) != NULL; } -/** - * @brief Attempt to receive a unit from the_mutex. - * - * This routine attempts to receive a unit from the_mutex. - * If a unit is available or if the wait flag is false, then the routine - * returns. Otherwise, the calling task is blocked until a unit becomes - * available. - * - * @param[in,out] executing The currently executing thread. - * @param[in,out] the_mutex is the mutex to attempt to lock - * @param[in] queue_context is the interrupt level - * - * @retval STATUS_UNAVAILABLE The mutex is already locked. - * @retval other Otherwise. - */ -RTEMS_INLINE_ROUTINE Status_Control _CORE_mutex_Seize_interrupt_trylock( - CORE_mutex_Control *the_mutex, - Thread_Control *executing, - Thread_queue_Context *queue_context -) -{ - /* disabled when you get here */ - - if ( !_CORE_mutex_Is_locked( the_mutex ) ) { - the_mutex->holder = executing; - the_mutex->nest_count = 1; - ++executing->resource_count; - - _CORE_mutex_Release( the_mutex, queue_context ); - return STATUS_SUCCESSFUL; - } - - /* - * At this point, we know the mutex was not available. If this thread - * is the thread that has locked the mutex, let's see if we are allowed - * to nest access. - */ - if ( _Thread_Is_executing( the_mutex->holder ) ) { - switch ( the_mutex->Attributes.lock_nesting_behavior ) { - case CORE_MUTEX_NESTING_ACQUIRES: - the_mutex->nest_count++; - _CORE_mutex_Release( the_mutex, queue_context ); - return STATUS_SUCCESSFUL; - #if defined(RTEMS_POSIX_API) - case CORE_MUTEX_NESTING_IS_ERROR: - _CORE_mutex_Release( the_mutex, queue_context ); - return STATUS_NESTING_NOT_ALLOWED; - #endif - } - } - - /* - * The mutex is not available and the caller must deal with the possibility - * of blocking. - */ - return STATUS_UNAVAILABLE; -} - -/** - * @brief Attempt to obtain the mutex. - * - * This routine attempts to obtain the mutex. If the mutex is available, - * then it will return immediately. Otherwise, it will invoke the - * support routine @a _Core_mutex_Seize_interrupt_blocking. - * - * @param[in] the_mutex is the mutex to attempt to lock - * @param[in] wait is true if the thread is willing to wait - * @param[in] timeout is the maximum number of ticks to block - * @param[in] queue_context is a temporary variable used to contain the ISR - * disable level cookie - * - * @note If the mutex is called from an interrupt service routine, - * with context switching disabled, or before multitasking, - * then a fatal error is generated. - * - * The logic on this routine is as follows: - * - * * If incorrect system state - * return an error - * * If mutex is available without any contention or blocking - * obtain it with interrupts disabled and returned - * * If the caller is willing to wait - * then they are blocked. - */ -RTEMS_INLINE_ROUTINE Status_Control _CORE_mutex_Seize( +Status_Control _CORE_mutex_Seize_slow( CORE_mutex_Control *the_mutex, Thread_Control *executing, + Thread_Control *owner, bool wait, Watchdog_Interval timeout, Thread_queue_Context *queue_context -) -{ - Status_Control status; - - _CORE_mutex_Acquire_critical( the_mutex, queue_context ); - - status = _CORE_mutex_Seize_interrupt_trylock( - the_mutex, - executing, - queue_context - ); - - if ( status != STATUS_UNAVAILABLE ) { - return status; - } - - if ( !wait ) { - _CORE_mutex_Release( the_mutex, queue_context ); - return status; - } - - return _CORE_mutex_Seize_interrupt_blocking( - the_mutex, - executing, - timeout, - queue_context - ); -} +); Status_Control _CORE_mutex_Seize_no_protocol_slow( CORE_mutex_Control *the_mutex, @@ -255,8 +113,11 @@ Status_Control _CORE_mutex_Seize_no_protocol_slow( Thread_queue_Context *queue_context ); -Status_Control _CORE_mutex_Surrender( +Status_Control _CORE_mutex_Surrender_slow( CORE_mutex_Control *the_mutex, + Thread_Control *executing, + Thread_queue_Heads *heads, + bool keep_priority, Thread_queue_Context *queue_context ); @@ -306,8 +167,7 @@ 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; + _CORE_mutex_Initialize( &the_mutex->Mutex ); the_mutex->nest_level = 0; } @@ -319,6 +179,99 @@ RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Seize_nested( return STATUS_SUCCESSFUL; } +RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Seize( + CORE_recursive_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->Mutex, queue_context ); + + owner = _CORE_mutex_Get_owner( &the_mutex->Mutex ); + + if ( owner == NULL ) { + _CORE_mutex_Set_owner( &the_mutex->Mutex, executing ); + ++executing->resource_count; + _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_slow( + &the_mutex->Mutex, + executing, + owner, + wait, + timeout, + queue_context + ); +} + +RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Surrender( + CORE_recursive_mutex_Control *the_mutex, + Thread_Control *executing, + Thread_queue_Context *queue_context +) +{ + unsigned int nest_level; + Thread_queue_Heads *heads; + bool keep_priority; + + _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; + } + + 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; + } + + --executing->resource_count; + _CORE_mutex_Set_owner( &the_mutex->Mutex, NULL ); + + /* + * Ensure that the owner resource count is visible to all other + * processors and that we read the latest priority restore + * hint. + */ + _Atomic_Fence( ATOMIC_ORDER_ACQ_REL ); + + heads = the_mutex->Mutex.Wait_queue.Queue.heads; + keep_priority = _Thread_Owns_resources( executing ) + || !executing->priority_restore_hint; + + if ( heads == NULL && keep_priority ) { + _CORE_mutex_Release( &the_mutex->Mutex, queue_context ); + return STATUS_SUCCESSFUL; + } + + return _CORE_mutex_Surrender_slow( + &the_mutex->Mutex, + executing, + heads, + keep_priority, + queue_context + ); +} + RTEMS_INLINE_ROUTINE Status_Control _CORE_recursive_mutex_Seize_no_protocol( CORE_recursive_mutex_Control *the_mutex, const Thread_queue_Operations *operations, diff --git a/cpukit/score/src/apimutex.c b/cpukit/score/src/apimutex.c index e3c6e5a705..ed5cfd5831 100644 --- a/cpukit/score/src/apimutex.c +++ b/cpukit/score/src/apimutex.c @@ -47,16 +47,12 @@ void _API_Mutex_Allocate( { API_Mutex_Control *mutex; - CORE_mutex_Attributes attr = { - CORE_MUTEX_NESTING_ACQUIRES - }; - mutex = (API_Mutex_Control *) _Objects_Allocate_unprotected( &_API_Mutex_Information ); _Assert( mutex != NULL ); - _CORE_mutex_Initialize( &mutex->Mutex, NULL, &attr, false ); + _CORE_recursive_mutex_Initialize( &mutex->Mutex ); _Objects_Open_u32( &_API_Mutex_Information, &mutex->Object, 1 ); diff --git a/cpukit/score/src/apimutexisowner.c b/cpukit/score/src/apimutexisowner.c index a80c664cb3..65b80ed5b3 100644 --- a/cpukit/score/src/apimutexisowner.c +++ b/cpukit/score/src/apimutexisowner.c @@ -18,9 +18,13 @@ #endif #include +#include #include bool _API_Mutex_Is_owner( const API_Mutex_Control *the_mutex ) { - return the_mutex->Mutex.holder == _Thread_Get_executing(); + return _CORE_mutex_Is_owner( + &the_mutex->Mutex.Mutex, + _Thread_Get_executing() + ); } diff --git a/cpukit/score/src/apimutexlock.c b/cpukit/score/src/apimutexlock.c index 7a7f911f84..df53e75256 100644 --- a/cpukit/score/src/apimutexlock.c +++ b/cpukit/score/src/apimutexlock.c @@ -34,15 +34,16 @@ void _API_Mutex_Lock( API_Mutex_Control *the_mutex ) _Thread_queue_Context_initialize( &queue_context ); _ISR_lock_ISR_disable( &queue_context.Lock_context ); - _CORE_mutex_Seize( + _CORE_recursive_mutex_Seize( &the_mutex->Mutex, _Thread_Executing, true, - 0, + WATCHDOG_NO_TIMEOUT, + _CORE_recursive_mutex_Seize_nested, &queue_context ); - if ( the_mutex->Mutex.nest_count == 1 ) { + if ( the_mutex->Mutex.nest_level == 0 ) { the_mutex->previous_thread_life_state = previous_thread_life_state; } } diff --git a/cpukit/score/src/apimutexunlock.c b/cpukit/score/src/apimutexunlock.c index 486301fa82..67188db144 100644 --- a/cpukit/score/src/apimutexunlock.c +++ b/cpukit/score/src/apimutexunlock.c @@ -29,11 +29,15 @@ void _API_Mutex_Unlock( API_Mutex_Control *the_mutex ) bool restore_thread_life_protection; previous_thread_life_state = the_mutex->previous_thread_life_state; - restore_thread_life_protection = the_mutex->Mutex.nest_count == 1; + restore_thread_life_protection = the_mutex->Mutex.nest_level == 0; _Thread_queue_Context_initialize( &queue_context ); _ISR_lock_ISR_disable( &queue_context.Lock_context ); - _CORE_mutex_Surrender( &the_mutex->Mutex, &queue_context ); + _CORE_recursive_mutex_Surrender( + &the_mutex->Mutex, + _Thread_Executing, + &queue_context + ); if ( restore_thread_life_protection ) { _Thread_Set_life_protection( previous_thread_life_state ); diff --git a/cpukit/score/src/coremutex.c b/cpukit/score/src/coremutex.c deleted file mode 100644 index 9c6b7a8b93..0000000000 --- a/cpukit/score/src/coremutex.c +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @file - * - * @brief Initialize a Core Mutex - * @ingroup ScoreMutex - */ - -/* - * COPYRIGHT (c) 1989-1999. - * On-Line Applications Research Corporation (OAR). - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include - -Status_Control _CORE_mutex_Initialize( - CORE_mutex_Control *the_mutex, - Thread_Control *executing, - const CORE_mutex_Attributes *the_mutex_attributes, - bool initially_locked -) -{ - -/* Add this to the RTEMS environment later ????????? - rtems_assert( initial_lock == CORE_MUTEX_LOCKED || - initial_lock == CORE_MUTEX_UNLOCKED ); - */ - - the_mutex->Attributes = *the_mutex_attributes; - - if ( initially_locked ) { - the_mutex->nest_count = 1; - the_mutex->holder = executing; - executing->resource_count++; - } else { - the_mutex->nest_count = 0; - the_mutex->holder = NULL; - } - - _Thread_queue_Initialize( &the_mutex->Wait_queue ); - - return STATUS_SUCCESSFUL; -} diff --git a/cpukit/score/src/coremutexseize.c b/cpukit/score/src/coremutexseize.c index ed5eb0aeec..ab743c4847 100644 --- a/cpukit/score/src/coremutexseize.c +++ b/cpukit/score/src/coremutexseize.c @@ -22,14 +22,19 @@ #include #include -Status_Control _CORE_mutex_Seize_interrupt_blocking( +Status_Control _CORE_mutex_Seize_slow( CORE_mutex_Control *the_mutex, Thread_Control *executing, + Thread_Control *owner, + bool wait, Watchdog_Interval timeout, Thread_queue_Context *queue_context ) { - Thread_Control *holder; + if ( !wait ) { + _CORE_mutex_Release( the_mutex, queue_context ); + return STATUS_UNAVAILABLE; + } #if !defined(RTEMS_SMP) /* @@ -37,23 +42,19 @@ Status_Control _CORE_mutex_Seize_interrupt_blocking( * priority inheritance mutexes. */ _Thread_Dispatch_disable(); -#endif - - holder = the_mutex->holder; -#if !defined(RTEMS_SMP) /* * To enable interrupts here works only since exactly one executing thread * exists and only threads are allowed to seize and surrender mutexes with * the priority inheritance protocol. On SMP configurations more than one * executing thread may exist, so here we must not release the lock, since - * otherwise the current holder may be no longer the holder of the mutex + * otherwise the current owner may be no longer the owner of the mutex * once we released the lock. */ _CORE_mutex_Release( the_mutex, queue_context ); #endif - _Thread_Inherit_priority( holder, executing ); + _Thread_Inherit_priority( owner, executing ); #if defined(RTEMS_SMP) _Thread_queue_Context_set_expected_level( queue_context, 1 ); diff --git a/cpukit/score/src/coremutexsurrender.c b/cpukit/score/src/coremutexsurrender.c index 5075e204c9..6604be89da 100644 --- a/cpukit/score/src/coremutexsurrender.c +++ b/cpukit/score/src/coremutexsurrender.c @@ -18,141 +18,58 @@ #include "config.h" #endif -#include -#include #include -#include -Status_Control _CORE_mutex_Surrender( +Status_Control _CORE_mutex_Surrender_slow( CORE_mutex_Control *the_mutex, + Thread_Control *executing, + Thread_queue_Heads *heads, + bool keep_priority, Thread_queue_Context *queue_context ) { - Thread_Control *the_thread; - Thread_Control *holder; + if ( heads != NULL ) { + const Thread_queue_Operations *operations; + Thread_Control *new_owner; + bool unblock; - holder = the_mutex->holder; + operations = CORE_MUTEX_TQ_OPERATIONS; + new_owner = ( *operations->first )( heads ); - /* - * Priority Ceiling or Priority Inheritance mutexes must be released by the - * thread which acquired them. - */ - 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 ); - - /* XXX already unlocked -- not right status */ - - if ( !the_mutex->nest_count ) { - _CORE_mutex_Release( the_mutex, queue_context ); - return STATUS_SUCCESSFUL; - } - - the_mutex->nest_count--; + _CORE_mutex_Set_owner( the_mutex, new_owner ); - if ( the_mutex->nest_count != 0 ) { - /* - * All error checking is on the locking side, so if the lock was - * allowed to acquired multiple times, then we should just deal with - * that. The RTEMS_DEBUG is just a validation. - */ - #if defined(RTEMS_DEBUG) - switch ( the_mutex->Attributes.lock_nesting_behavior ) { - case CORE_MUTEX_NESTING_ACQUIRES: - _CORE_mutex_Release( the_mutex, queue_context ); - return STATUS_SUCCESSFUL; - #if defined(RTEMS_POSIX_API) - case CORE_MUTEX_NESTING_IS_ERROR: - /* should never occur */ - _CORE_mutex_Release( the_mutex, queue_context ); - return STATUS_NESTING_NOT_ALLOWED; - #endif - } - #else - _CORE_mutex_Release( the_mutex, queue_context ); - /* must be CORE_MUTEX_NESTING_ACQUIRES or we wouldn't be here */ - return STATUS_SUCCESSFUL; - #endif - } - - /* - * Formally release the mutex before possibly transferring it to a - * blocked thread. - */ - holder->resource_count--; - the_mutex->holder = NULL; - - /* - * Now we check if another thread was waiting for this mutex. If so, - * transfer the mutex to that thread. - */ - if ( - ( the_thread = _Thread_queue_First_locked( - &the_mutex->Wait_queue, - CORE_MUTEX_TQ_OPERATIONS - ) - ) - ) { - bool unblock; - - the_mutex->holder = the_thread; - the_mutex->nest_count = 1; - - /* - * 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->Wait_queue.Queue, - CORE_MUTEX_TQ_OPERATIONS, - the_thread, + operations, + new_owner, queue_context ); #if defined(RTEMS_MULTIPROCESSING) - if ( _Objects_Is_local_id( the_thread->Object.id ) ) + if ( _Objects_Is_local_id( new_owner->Object.id ) ) #endif { - the_thread->resource_count++; - _Thread_queue_Boost_priority( &the_mutex->Wait_queue.Queue, the_thread ); + ++new_owner->resource_count; + _Thread_queue_Boost_priority( &the_mutex->Wait_queue.Queue, new_owner ); } _Thread_queue_Unblock_critical( unblock, &the_mutex->Wait_queue.Queue, - the_thread, + new_owner, &queue_context->Lock_context ); } else { _CORE_mutex_Release( the_mutex, queue_context ); } - /* - * 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( holder ) ) { - /* - * Ensure that the holder resource count is visible to all other processors - * and that we read the latest priority restore hint. - */ - _Atomic_Fence( ATOMIC_ORDER_ACQ_REL ); - - if ( holder->priority_restore_hint ) { - Per_CPU_Control *cpu_self; + if ( !keep_priority ) { + Per_CPU_Control *cpu_self; - cpu_self = _Thread_Dispatch_disable(); - _Thread_Restore_priority( holder ); - _Thread_Dispatch_enable( cpu_self ); - } + cpu_self = _Thread_Dispatch_disable(); + _Thread_Restore_priority( executing ); + _Thread_Dispatch_enable( cpu_self ); } - _CORE_mutex_Restore_priority( holder ); return STATUS_SUCCESSFUL; } diff --git a/cpukit/score/src/debugisownerofallocator.c b/cpukit/score/src/debugisownerofallocator.c index 57da2ca001..6b396df4fc 100644 --- a/cpukit/score/src/debugisownerofallocator.c +++ b/cpukit/score/src/debugisownerofallocator.c @@ -27,7 +27,7 @@ bool owner; if ( mutex != NULL ) { - owner = mutex->Mutex.holder == _Thread_Get_executing(); + owner = _API_Mutex_Is_owner( mutex ); } else { owner = false; } -- cgit v1.2.3