[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