[rtems commit] score: Fine grained locking for mutexes

Sebastian Huber sebh at rtems.org
Wed May 20 07:12:03 UTC 2015


Module:    rtems
Branch:    master
Commit:    4438ac2575fb9e0760bf53931a52d00dec4deb83
Changeset: http://git.rtems.org/rtems/commit/?id=4438ac2575fb9e0760bf53931a52d00dec4deb83

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Sat May  2 14:27:24 2015 +0200

score: Fine grained locking for mutexes

Update #2273.

---

 cpukit/libnetworking/rtems/rtems_glue.c          | 19 ++----
 cpukit/posix/src/mutexlocksupp.c                 |  7 --
 cpukit/posix/src/mutexsetprioceiling.c           | 11 ++-
 cpukit/posix/src/mutexunlock.c                   | 11 ++-
 cpukit/rtems/src/semobtain.c                     |  7 --
 cpukit/rtems/src/semrelease.c                    |  6 +-
 cpukit/score/include/rtems/score/coremuteximpl.h | 40 ++++++-----
 cpukit/score/src/apimutexlock.c                  |  8 ---
 cpukit/score/src/apimutexunlock.c                | 17 +++--
 cpukit/score/src/coremutex.c                     |  5 +-
 cpukit/score/src/coremutexseize.c                | 30 ++++++---
 cpukit/score/src/coremutexsurrender.c            | 86 +++++++++++++++++-------
 cpukit/score/src/debugisownerofallocator.c       | 13 +---
 13 files changed, 143 insertions(+), 117 deletions(-)

diff --git a/cpukit/libnetworking/rtems/rtems_glue.c b/cpukit/libnetworking/rtems/rtems_glue.c
index 63d4b80..e43dc6e 100644
--- a/cpukit/libnetworking/rtems/rtems_glue.c
+++ b/cpukit/libnetworking/rtems/rtems_glue.c
@@ -378,9 +378,6 @@ rtems_bsdnet_semaphore_obtain (void)
 #ifdef RTEMS_FAST_MUTEX
 	ISR_lock_Context lock_context;
 	Thread_Control *executing;
-#ifdef RTEMS_SMP
-	_Thread_Disable_dispatch();
-#endif
 	_ISR_lock_ISR_disable(&lock_context);
 	if (!the_networkSemaphore)
 		rtems_panic ("rtems-net: network sema obtain: network not initialised\n");
@@ -393,9 +390,6 @@ rtems_bsdnet_semaphore_obtain (void)
 		0,		/* forever */
 		&lock_context
 		);
-#ifdef RTEMS_SMP
-	_Thread_Enable_dispatch();
-#endif
 	if (executing->Wait.return_code)
 		rtems_panic ("rtems-net: can't obtain network sema: %d\n",
                  executing->Wait.return_code);
@@ -416,18 +410,19 @@ void
 rtems_bsdnet_semaphore_release (void)
 {
 #ifdef RTEMS_FAST_MUTEX
-	int i;
+        ISR_lock_Context lock_context;
+	CORE_mutex_Status status;
 
-	_Thread_Disable_dispatch();
 	if (!the_networkSemaphore)
 		rtems_panic ("rtems-net: network sema obtain: network not initialised\n");
-	i = _CORE_mutex_Surrender (
+        _ISR_lock_ISR_disable(&lock_context);
+	status = _CORE_mutex_Surrender (
 		&the_networkSemaphore->Core_control.mutex,
 		networkSemaphore,
-		NULL
+		NULL,
+                &lock_context
 		);
-	_Thread_Enable_dispatch();
-	if (i)
+	if (status != CORE_MUTEX_STATUS_SUCCESSFUL)
 		rtems_panic ("rtems-net: can't release network sema: %i\n");
 #else
 	rtems_status_code sc;
diff --git a/cpukit/posix/src/mutexlocksupp.c b/cpukit/posix/src/mutexlocksupp.c
index 9b20f58..b63a89a 100644
--- a/cpukit/posix/src/mutexlocksupp.c
+++ b/cpukit/posix/src/mutexlocksupp.c
@@ -54,9 +54,6 @@ int _POSIX_Mutex_Lock_support(
   switch ( location ) {
 
     case OBJECTS_LOCAL:
-#if defined(RTEMS_SMP)
-      _Thread_Disable_dispatch();
-#endif
       executing = _Thread_Executing;
       _CORE_mutex_Seize(
         &the_mutex->Mutex,
@@ -66,10 +63,6 @@ int _POSIX_Mutex_Lock_support(
         timeout,
         &lock_context
       );
-#if defined(RTEMS_SMP)
-      _Thread_Enable_dispatch();
-#endif
-      _Objects_Put_for_get_isr_disable( &the_mutex->Object );
       return _POSIX_Mutex_Translate_core_mutex_return_code(
         (CORE_mutex_Status) executing->Wait.return_code
       );
diff --git a/cpukit/posix/src/mutexsetprioceiling.c b/cpukit/posix/src/mutexsetprioceiling.c
index f0fb8f5..32d9210 100644
--- a/cpukit/posix/src/mutexsetprioceiling.c
+++ b/cpukit/posix/src/mutexsetprioceiling.c
@@ -41,6 +41,7 @@ int pthread_mutex_setprioceiling(
   register POSIX_Mutex_Control *the_mutex;
   Objects_Locations             location;
   Priority_Control              the_priority;
+  ISR_lock_Context              lock_context;
 
   if ( !old_ceiling )
     return EINVAL;
@@ -64,7 +65,11 @@ int pthread_mutex_setprioceiling(
    *  NOTE: This makes it easier to get 100% binary coverage since the
    *        bad Id case is handled by the switch.
    */
-  the_mutex = _POSIX_Mutex_Get( mutex, &location );
+  the_mutex = _POSIX_Mutex_Get_interrupt_disable(
+    mutex,
+    &location,
+    &lock_context
+  );
   switch ( location ) {
 
     case OBJECTS_LOCAL:
@@ -78,9 +83,9 @@ int pthread_mutex_setprioceiling(
       _CORE_mutex_Surrender(
         &the_mutex->Mutex,
         the_mutex->Object.id,
-        NULL
+        NULL,
+        &lock_context
       );
-      _Objects_Put( &the_mutex->Object );
 
       return 0;
 
diff --git a/cpukit/posix/src/mutexunlock.c b/cpukit/posix/src/mutexunlock.c
index dbb9d1a..c5b2375 100644
--- a/cpukit/posix/src/mutexunlock.c
+++ b/cpukit/posix/src/mutexunlock.c
@@ -41,17 +41,22 @@ int pthread_mutex_unlock(
   register POSIX_Mutex_Control *the_mutex;
   Objects_Locations             location;
   CORE_mutex_Status             status;
+  ISR_lock_Context              lock_context;
 
-  the_mutex = _POSIX_Mutex_Get( mutex, &location );
+  the_mutex = _POSIX_Mutex_Get_interrupt_disable(
+    mutex,
+    &location,
+    &lock_context
+  );
   switch ( location ) {
 
     case OBJECTS_LOCAL:
       status = _CORE_mutex_Surrender(
         &the_mutex->Mutex,
         the_mutex->Object.id,
-        NULL
+        NULL,
+        &lock_context
       );
-      _Objects_Put( &the_mutex->Object );
       return _POSIX_Mutex_Translate_core_mutex_return_code( status );
 
 #if defined(RTEMS_MULTIPROCESSING)
diff --git a/cpukit/rtems/src/semobtain.c b/cpukit/rtems/src/semobtain.c
index 46d1b82..1ebc98b 100644
--- a/cpukit/rtems/src/semobtain.c
+++ b/cpukit/rtems/src/semobtain.c
@@ -73,9 +73,6 @@ rtems_status_code rtems_semaphore_obtain(
       } else
 #endif
       if ( !_Attributes_Is_counting_semaphore( attribute_set ) ) {
-#if defined(RTEMS_SMP)
-        _Thread_Disable_dispatch();
-#endif
         _CORE_mutex_Seize(
           &the_semaphore->Core_control.mutex,
           executing,
@@ -84,10 +81,6 @@ rtems_status_code rtems_semaphore_obtain(
           timeout,
           &lock_context
         );
-#if defined(RTEMS_SMP)
-        _Thread_Enable_dispatch();
-#endif
-        _Objects_Put_for_get_isr_disable( &the_semaphore->Object );
         return _Semaphore_Translate_core_mutex_return_code(
                   executing->Wait.return_code );
       }
diff --git a/cpukit/rtems/src/semrelease.c b/cpukit/rtems/src/semrelease.c
index 1f0581e..7e4b98e 100644
--- a/cpukit/rtems/src/semrelease.c
+++ b/cpukit/rtems/src/semrelease.c
@@ -86,14 +86,12 @@ rtems_status_code rtems_semaphore_release(
       } else
 #endif
       if ( !_Attributes_Is_counting_semaphore( attribute_set ) ) {
-        _Thread_Disable_dispatch();
-        _ISR_lock_ISR_enable( &lock_context );
         mutex_status = _CORE_mutex_Surrender(
           &the_semaphore->Core_control.mutex,
           id,
-          MUTEX_MP_SUPPORT
+          MUTEX_MP_SUPPORT,
+          &lock_context
         );
-        _Thread_Enable_dispatch();
         return _Semaphore_Translate_core_mutex_return_code( mutex_status );
       } else {
         semaphore_status = _CORE_semaphore_Surrender(
diff --git a/cpukit/score/include/rtems/score/coremuteximpl.h b/cpukit/score/include/rtems/score/coremuteximpl.h
index a681168..54dadbe 100644
--- a/cpukit/score/include/rtems/score/coremuteximpl.h
+++ b/cpukit/score/include/rtems/score/coremuteximpl.h
@@ -210,17 +210,10 @@ void _CORE_mutex_Seize_interrupt_blocking(
  *
  *  @retval this method returns true if dispatch is in an unsafe state.
  */
-#ifdef RTEMS_SMP
-  #define _CORE_mutex_Check_dispatch_for_seize(_wait) \
-      (_Thread_Dispatch_get_disable_level() != 1 \
-        && (_wait) \
-        && (_System_state_Get() >= SYSTEM_STATE_UP))
-#else
-  #define _CORE_mutex_Check_dispatch_for_seize(_wait) \
-      (!_Thread_Dispatch_is_enabled() \
-        && (_wait) \
-        && (_System_state_Get() >= SYSTEM_STATE_UP))
-#endif
+#define _CORE_mutex_Check_dispatch_for_seize(_wait) \
+  (!_Thread_Dispatch_is_enabled() \
+    && (_wait) \
+    && (_System_state_Get() >= SYSTEM_STATE_UP))
 
 /**
  *  @brief Attempt to obtain the mutex.
@@ -265,9 +258,10 @@ RTEMS_INLINE_ROUTINE void _CORE_mutex_Seize_body(
       INTERNAL_ERROR_MUTEX_OBTAIN_FROM_BAD_STATE
     );
   }
+  _Thread_queue_Acquire_critical( &the_mutex->Wait_queue, lock_context );
   if ( _CORE_mutex_Seize_interrupt_trylock( the_mutex, executing, lock_context ) ) {
     if ( !wait ) {
-      _ISR_lock_ISR_enable( lock_context );
+      _Thread_queue_Release( &the_mutex->Wait_queue, lock_context );
       executing->Wait.return_code =
         CORE_MUTEX_STATUS_UNSATISFIED_NOWAIT;
     } else {
@@ -320,13 +314,15 @@ RTEMS_INLINE_ROUTINE void _CORE_mutex_Seize_body(
  *  @param[in] id is the id of the RTEMS Object associated with this mutex
  *  @param[in] api_mutex_mp_support is the routine that will be called when
  *         unblocking a remote mutex
+ *  @param[in] lock_context is the interrupt level
  *
  *  @retval an indication of whether the routine succeeded or failed
  */
 CORE_mutex_Status _CORE_mutex_Surrender(
   CORE_mutex_Control                *the_mutex,
   Objects_Id                         id,
-  CORE_mutex_API_mp_support_callout  api_mutex_mp_support
+  CORE_mutex_API_mp_support_callout  api_mutex_mp_support,
+  ISR_lock_Context                  *lock_context
 );
 
 /**
@@ -472,7 +468,7 @@ RTEMS_INLINE_ROUTINE int _CORE_mutex_Seize_interrupt_trylock_body(
     }
 
     if ( !_CORE_mutex_Is_priority_ceiling( &the_mutex->Attributes ) ) {
-      _ISR_lock_ISR_enable( lock_context );
+      _Thread_queue_Release( &the_mutex->Wait_queue, lock_context );
       return 0;
     } /* else must be CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING
        *
@@ -486,19 +482,21 @@ RTEMS_INLINE_ROUTINE int _CORE_mutex_Seize_interrupt_trylock_body(
       ceiling = the_mutex->Attributes.priority_ceiling;
       current = executing->current_priority;
       if ( current == ceiling ) {
-        _ISR_lock_ISR_enable( lock_context );
+        _Thread_queue_Release( &the_mutex->Wait_queue, lock_context );
         return 0;
       }
 
       if ( current > ceiling ) {
-        _Thread_Disable_dispatch();
-        _ISR_lock_ISR_enable( lock_context );
+        Per_CPU_Control *cpu_self;
+
+        cpu_self = _Thread_Dispatch_disable_critical();
+        _Thread_queue_Release( &the_mutex->Wait_queue, lock_context );
         _Thread_Change_priority(
           executing,
           ceiling,
           false
         );
-        _Thread_Enable_dispatch();
+        _Thread_Dispatch_enable( cpu_self );
         return 0;
       }
       /* if ( current < ceiling ) */ {
@@ -506,7 +504,7 @@ RTEMS_INLINE_ROUTINE int _CORE_mutex_Seize_interrupt_trylock_body(
         the_mutex->holder = NULL;
         the_mutex->nest_count = 0;     /* undo locking above */
         executing->resource_count--;   /* undo locking above */
-        _ISR_lock_ISR_enable( lock_context );
+        _Thread_queue_Release( &the_mutex->Wait_queue, lock_context );
         return 0;
       }
     }
@@ -522,12 +520,12 @@ RTEMS_INLINE_ROUTINE int _CORE_mutex_Seize_interrupt_trylock_body(
     switch ( the_mutex->Attributes.lock_nesting_behavior ) {
       case CORE_MUTEX_NESTING_ACQUIRES:
         the_mutex->nest_count++;
-        _ISR_lock_ISR_enable( lock_context );
+        _Thread_queue_Release( &the_mutex->Wait_queue, lock_context );
         return 0;
       #if defined(RTEMS_POSIX_API)
         case CORE_MUTEX_NESTING_IS_ERROR:
           executing->Wait.return_code = CORE_MUTEX_STATUS_NESTING_NOT_ALLOWED;
-          _ISR_lock_ISR_enable( lock_context );
+          _Thread_queue_Release( &the_mutex->Wait_queue, lock_context );
           return 0;
       #endif
       case CORE_MUTEX_NESTING_BLOCKS:
diff --git a/cpukit/score/src/apimutexlock.c b/cpukit/score/src/apimutexlock.c
index 45ad0ba..bcac71a 100644
--- a/cpukit/score/src/apimutexlock.c
+++ b/cpukit/score/src/apimutexlock.c
@@ -30,10 +30,6 @@ void _API_Mutex_Lock( API_Mutex_Control *the_mutex )
 
   previous_thread_life_protection = _Thread_Set_life_protection( true );
 
-  #if defined(RTEMS_SMP)
-    _Thread_Disable_dispatch();
-  #endif
-
   _ISR_lock_ISR_disable( &lock_context );
 
   _CORE_mutex_Seize(
@@ -49,8 +45,4 @@ void _API_Mutex_Lock( API_Mutex_Control *the_mutex )
     the_mutex->previous_thread_life_protection =
       previous_thread_life_protection;
   }
-
-  #if defined(RTEMS_SMP)
-    _Thread_Enable_dispatch();
-  #endif
 }
diff --git a/cpukit/score/src/apimutexunlock.c b/cpukit/score/src/apimutexunlock.c
index d0432a6..04657dd 100644
--- a/cpukit/score/src/apimutexunlock.c
+++ b/cpukit/score/src/apimutexunlock.c
@@ -24,18 +24,21 @@
 
 void _API_Mutex_Unlock( API_Mutex_Control *the_mutex )
 {
-  bool previous_thread_life_protection;
-  bool restore_thread_life_protection;
-
-  _Thread_Disable_dispatch();
+  ISR_lock_Context lock_context;
+  bool             previous_thread_life_protection;
+  bool             restore_thread_life_protection;
 
   previous_thread_life_protection =
     the_mutex->previous_thread_life_protection;
   restore_thread_life_protection = the_mutex->Mutex.nest_count == 1;
 
-  _CORE_mutex_Surrender( &the_mutex->Mutex, the_mutex->Object.id, NULL );
-
-  _Thread_Enable_dispatch();
+  _ISR_lock_ISR_disable( &lock_context );
+  _CORE_mutex_Surrender(
+    &the_mutex->Mutex,
+    the_mutex->Object.id,
+    NULL,
+    &lock_context
+  );
 
   if ( restore_thread_life_protection ) {
     _Thread_Set_life_protection( previous_thread_life_protection );
diff --git a/cpukit/score/src/coremutex.c b/cpukit/score/src/coremutex.c
index 2f584f2..58c6c42 100644
--- a/cpukit/score/src/coremutex.c
+++ b/cpukit/score/src/coremutex.c
@@ -48,13 +48,14 @@ CORE_mutex_Status _CORE_mutex_Initialize(
     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 in
        * general.  Disable thread dispatching before the priority check to
        * prevent interference with priority inheritance.
        */
-      _Thread_Disable_dispatch();
+      cpu_self = _Thread_Dispatch_disable();
 
       if ( is_priority_ceiling && executing->current_priority < ceiling ) {
         _Thread_Enable_dispatch();
@@ -73,7 +74,7 @@ CORE_mutex_Status _CORE_mutex_Initialize(
         _Thread_Change_priority( executing, ceiling, false );
       }
 
-      _Thread_Enable_dispatch();
+      _Thread_Dispatch_enable( cpu_self );
     }
   } else {
     the_mutex->nest_count = 0;
diff --git a/cpukit/score/src/coremutexseize.c b/cpukit/score/src/coremutexseize.c
index 4ecb702..94c480d 100644
--- a/cpukit/score/src/coremutexseize.c
+++ b/cpukit/score/src/coremutexseize.c
@@ -53,17 +53,28 @@ void _CORE_mutex_Seize_interrupt_blocking(
   ISR_lock_Context    *lock_context
 )
 {
-  _Thread_Disable_dispatch();
+#if !defined(RTEMS_SMP)
+  /*
+   * We must disable thread dispatching here since we enable the interrupts for
+   * priority inheritance mutexes.
+   */
+  _Thread_Dispatch_disable();
+#endif
 
   if ( _CORE_mutex_Is_inherit_priority( &the_mutex->Attributes ) ) {
     Thread_Control *holder = the_mutex->holder;
 
+#if !defined(RTEMS_SMP)
     /*
-     * To enable interrupts here works only since we own the Giant lock and
-     * only threads are allowed to seize and surrender mutexes with the
-     * priority inheritance protocol.
+     * 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
+     * once we released the lock.
      */
-    _ISR_lock_ISR_enable( lock_context );
+    _Thread_queue_Release( &the_mutex->Wait_queue, lock_context );
+#endif
 
     _Scheduler_Change_priority_if_higher(
       _Scheduler_Get( holder ),
@@ -72,10 +83,11 @@ void _CORE_mutex_Seize_interrupt_blocking(
       false
     );
 
-    _ISR_lock_ISR_disable( lock_context );
+#if !defined(RTEMS_SMP)
+    _Thread_queue_Acquire( &the_mutex->Wait_queue, lock_context );
+#endif
   }
 
-  _Thread_queue_Acquire_critical( &the_mutex->Wait_queue, lock_context );
   _Thread_queue_Enqueue_critical(
     &the_mutex->Wait_queue,
     executing,
@@ -85,6 +97,8 @@ void _CORE_mutex_Seize_interrupt_blocking(
     lock_context
   );
 
-  _Thread_Enable_dispatch();
+#if !defined(RTEMS_SMP)
+  _Thread_Dispatch_enable( _Per_CPU_Get() );
+#endif
 }
 
diff --git a/cpukit/score/src/coremutexsurrender.c b/cpukit/score/src/coremutexsurrender.c
index 8fba301..3f0cd86 100644
--- a/cpukit/score/src/coremutexsurrender.c
+++ b/cpukit/score/src/coremutexsurrender.c
@@ -89,11 +89,12 @@ CORE_mutex_Status _CORE_mutex_Surrender(
   CORE_mutex_Control                *the_mutex,
 #if defined(RTEMS_MULTIPROCESSING)
   Objects_Id                         id,
-  CORE_mutex_API_mp_support_callout  api_mutex_mp_support
+  CORE_mutex_API_mp_support_callout  api_mutex_mp_support,
 #else
   Objects_Id                         id __attribute__((unused)),
-  CORE_mutex_API_mp_support_callout  api_mutex_mp_support __attribute__((unused))
+  CORE_mutex_API_mp_support_callout  api_mutex_mp_support __attribute__((unused)),
 #endif
+  ISR_lock_Context                  *lock_context
 )
 {
   Thread_Control *the_thread;
@@ -110,14 +111,20 @@ CORE_mutex_Status _CORE_mutex_Surrender(
    */
 
   if ( the_mutex->Attributes.only_owner_release ) {
-    if ( !_Thread_Is_executing( holder ) )
+    if ( !_Thread_Is_executing( holder ) ) {
+      _ISR_lock_ISR_enable( lock_context );
       return CORE_MUTEX_STATUS_NOT_OWNER_OF_RESOURCE;
+    }
   }
 
+  _Thread_queue_Acquire_critical( &the_mutex->Wait_queue, lock_context );
+
   /* XXX already unlocked -- not right status */
 
-  if ( !the_mutex->nest_count )
+  if ( !the_mutex->nest_count ) {
+    _Thread_queue_Release( &the_mutex->Wait_queue, lock_context );
     return CORE_MUTEX_STATUS_SUCCESSFUL;
+  }
 
   the_mutex->nest_count--;
 
@@ -130,10 +137,12 @@ CORE_mutex_Status _CORE_mutex_Surrender(
     #if defined(RTEMS_DEBUG)
       switch ( the_mutex->Attributes.lock_nesting_behavior ) {
         case CORE_MUTEX_NESTING_ACQUIRES:
+          _Thread_queue_Release( &the_mutex->Wait_queue, lock_context );
           return CORE_MUTEX_STATUS_SUCCESSFUL;
         #if defined(RTEMS_POSIX_API)
           case CORE_MUTEX_NESTING_IS_ERROR:
             /* should never occur */
+            _Thread_queue_Release( &the_mutex->Wait_queue, lock_context );
             return CORE_MUTEX_STATUS_NESTING_NOT_ALLOWED;
         #endif
         case CORE_MUTEX_NESTING_BLOCKS:
@@ -141,6 +150,7 @@ CORE_mutex_Status _CORE_mutex_Surrender(
           break;
       }
     #else
+      _Thread_queue_Release( &the_mutex->Wait_queue, lock_context );
       /* must be CORE_MUTEX_NESTING_ACQUIRES or we wouldn't be here */
       return CORE_MUTEX_STATUS_SUCCESSFUL;
     #endif
@@ -155,20 +165,12 @@ CORE_mutex_Status _CORE_mutex_Surrender(
     CORE_mutex_Status pop_status =
       _CORE_mutex_Pop_priority( the_mutex, holder );
 
-    if ( pop_status != CORE_MUTEX_STATUS_SUCCESSFUL )
+    if ( pop_status != CORE_MUTEX_STATUS_SUCCESSFUL ) {
+      _Thread_queue_Release( &the_mutex->Wait_queue, lock_context );
       return pop_status;
+    }
 
     holder->resource_count--;
-
-    /*
-     *  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 ) &&
-         holder->real_priority != holder->current_priority ) {
-      _Thread_Change_priority( holder, holder->real_priority, true );
-    }
   }
   the_mutex->holder = NULL;
 
@@ -176,20 +178,21 @@ CORE_mutex_Status _CORE_mutex_Surrender(
    *  Now we check if another thread was waiting for this mutex.  If so,
    *  transfer the mutex to that thread.
    */
-  if ( ( the_thread = _Thread_queue_Dequeue( &the_mutex->Wait_queue ) ) ) {
+  if ( ( the_thread = _Thread_queue_First_locked( &the_mutex->Wait_queue ) ) ) {
+    /*
+     * 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.
+     */
+    _Thread_queue_Extract_locked( &the_mutex->Wait_queue, the_thread );
 
 #if defined(RTEMS_MULTIPROCESSING)
-    if ( !_Objects_Is_local_id( the_thread->Object.id ) ) {
-
-      the_mutex->holder     = NULL;
-      the_mutex->nest_count = 1;
+    _Thread_Dispatch_disable();
 
-      ( *api_mutex_mp_support)( the_thread, id );
-
-    } else
+    if ( _Objects_Is_local_id( the_thread->Object.id ) )
 #endif
     {
-
       the_mutex->holder     = the_thread;
       the_mutex->nest_count = 1;
 
@@ -215,6 +218,41 @@ CORE_mutex_Status _CORE_mutex_Surrender(
           break;
       }
     }
+
+    _Thread_queue_Unblock_critical(
+      &the_mutex->Wait_queue,
+      the_thread,
+      lock_context
+    );
+
+#if defined(RTEMS_MULTIPROCESSING)
+    if ( !_Objects_Is_local_id( the_thread->Object.id ) ) {
+
+      the_mutex->holder     = NULL;
+      the_mutex->nest_count = 1;
+
+      ( *api_mutex_mp_support)( the_thread, id );
+
+    }
+
+    _Thread_Dispatch_enable( _Per_CPU_Get() );
+#endif
+  } else {
+    _Thread_queue_Release( &the_mutex->Wait_queue, lock_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 ) &&
+       holder->real_priority != holder->current_priority ) {
+    Per_CPU_Control *cpu_self;
+
+    cpu_self = _Thread_Dispatch_disable();
+    _Thread_Change_priority( holder, holder->real_priority, true );
+    _Thread_Dispatch_enable( cpu_self );
   }
 
   return CORE_MUTEX_STATUS_SUCCESSFUL;
diff --git a/cpukit/score/src/debugisownerofallocator.c b/cpukit/score/src/debugisownerofallocator.c
index 7879902..57da2ca 100644
--- a/cpukit/score/src/debugisownerofallocator.c
+++ b/cpukit/score/src/debugisownerofallocator.c
@@ -18,8 +18,7 @@
 
 #include <rtems/score/assert.h>
 #include <rtems/score/apimutex.h>
-#include <rtems/score/thread.h>
-#include <rtems/score/threaddispatch.h>
+#include <rtems/score/threadimpl.h>
 
 #if defined( RTEMS_DEBUG )
   bool _Debug_Is_owner_of_allocator( void )
@@ -27,20 +26,12 @@
     API_Mutex_Control *mutex = _RTEMS_Allocator_Mutex;
     bool owner;
 
-    /*
-     * We have to synchronize with the _CORE_mutex_Surrender() operation,
-     * otherwise we may observe an outdated mutex holder.
-     */
-    _Thread_Disable_dispatch();
-
     if ( mutex != NULL ) {
-      owner = mutex->Mutex.holder == _Thread_Executing;
+      owner = mutex->Mutex.holder == _Thread_Get_executing();
     } else {
       owner = false;
     }
 
-    _Thread_Enable_dispatch();
-
     return owner;
   }
 #endif




More information about the vc mailing list