[PATCH 12/12] score: Add CORE mutex variants
Sebastian Huber
sebastian.huber at embedded-brains.de
Fri May 27 13:50:41 UTC 2016
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
More information about the devel
mailing list