[PATCH 2/3] score: Add thread lock

Sebastian Huber sebastian.huber at embedded-brains.de
Mon Mar 23 14:51:46 UTC 2015


Update #2273.
---
 cpukit/score/include/rtems/score/thread.h     |  44 ++++++++++
 cpukit/score/include/rtems/score/threadimpl.h | 122 ++++++++++++++++++++++++++
 cpukit/score/src/threadchangepriority.c       |  19 ++--
 cpukit/score/src/threadinitialize.c           |   3 +
 cpukit/score/src/threadrestart.c              |   4 +
 5 files changed, 186 insertions(+), 6 deletions(-)

diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h
index ee7886c..ef238a3 100644
--- a/cpukit/score/include/rtems/score/thread.h
+++ b/cpukit/score/include/rtems/score/thread.h
@@ -618,6 +618,42 @@ typedef struct  {
   void *        control;
 }Thread_Capture_control;
 
+#if defined(RTEMS_SMP)
+/**
+ * @brief Thread lock control.
+ *
+ * The thread lock is either the default lock or the lock of the resource on
+ * which the thread is currently blocked.  The generation number takes care
+ * that the up to date lock is used.  Only resources using fine grained locking
+ * provide their own lock.
+ *
+ * The thread lock protects the following thread variables
+ *  - Thread_Control::current_priority,
+ *  - Thread_Control::Priority::change_handler, and
+ *  - Thread_Control::Priority::change_handler_context.
+ *
+ * @see _Thread_Lock_acquire(), _Thread_Lock_release(), _Thread_Lock_set() and
+ * _Thread_Lock_restore_default().
+ */
+typedef struct {
+  /**
+   * @brief The current thread lock.
+   */
+  ISR_lock_Control *current;
+
+  /**
+   * @brief The default thread lock in case the thread is not blocked on a
+   * resource.
+   */
+  ISR_lock_Control Default;
+
+  /**
+   * @brief Generation number to invalidate stale locks.
+   */
+  Atomic_Uint generation;
+} Thread_Lock_control;
+#endif
+
 /**
  *  This structure defines the Thread Control Block (TCB).
  */
@@ -640,6 +676,14 @@ struct Thread_Control_struct {
 
   /** This field is the number of mutexes currently held by this thread. */
   uint32_t                 resource_count;
+
+#if defined(RTEMS_SMP)
+  /**
+   * @brief Thread lock control.
+   */
+  Thread_Lock_control Lock;
+#endif
+
   /** This field is the blocking information for this thread. */
   Thread_Wait_information  Wait;
   /** This field is the Watchdog used to manage thread delays and timeouts. */
diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h
index 5376ce1..e45ceb7 100644
--- a/cpukit/score/include/rtems/score/threadimpl.h
+++ b/cpukit/score/include/rtems/score/threadimpl.h
@@ -883,6 +883,128 @@ RTEMS_INLINE_ROUTINE bool _Thread_Owns_resources(
   return owns_resources;
 }
 
+/**
+ * @brief Release the thread lock.
+ *
+ * @param[in] lock The lock returned by _Thread_Lock_acquire().
+ * @param[in] lock_context The lock context used for _Thread_Lock_acquire().
+ */
+RTEMS_INLINE_ROUTINE void _Thread_Lock_release(
+  ISR_lock_Control *lock,
+  ISR_lock_Context *lock_context
+)
+{
+  _ISR_lock_Release_and_ISR_enable( lock, lock_context );
+}
+
+/**
+ * @brief Acquires the thread lock.
+ *
+ * @param[in] the_thread The thread.
+ * @param[in] lock_context The lock context for _Thread_Lock_release().
+ *
+ * @return The lock required by _Thread_Lock_release().
+ */
+RTEMS_INLINE_ROUTINE ISR_lock_Control *_Thread_Lock_acquire(
+  Thread_Control   *the_thread,
+  ISR_lock_Context *lock_context
+)
+{
+#if defined(RTEMS_SMP)
+  ISR_lock_Control *lock;
+
+  while ( true ) {
+    uint32_t my_generation;
+
+    _ISR_Disable_without_giant( lock_context->Lock_context.isr_level );
+    my_generation = the_thread->Lock.generation;
+
+    _Atomic_Fence( ATOMIC_ORDER_ACQUIRE );
+
+    lock = the_thread->Lock.current;
+    _ISR_lock_Acquire( lock, lock_context );
+
+    _Atomic_Fence( ATOMIC_ORDER_ACQUIRE );
+
+    if ( the_thread->Lock.generation == my_generation ) {
+      break;
+    }
+
+    _Thread_Lock_release( lock, lock_context );
+  }
+
+  return lock;
+#else
+  _ISR_Disable( lock_context->isr_level );
+
+  return NULL;
+#endif
+}
+
+RTEMS_INLINE_ROUTINE void _Thread_Lock_set_unprotected(
+  Thread_Control   *the_thread,
+  ISR_lock_Control *new_lock
+)
+{
+#if defined(RTEMS_SMP)
+  the_thread->Lock.current = new_lock;
+
+  _Atomic_Fence( ATOMIC_ORDER_RELEASE );
+
+  _Atomic_Fetch_add_uint(
+    &the_thread->Lock.generation,
+    1,
+    ATOMIC_ORDER_RELAXED
+  );
+#else
+  (void) the_thread;
+  (void) new_lock;
+#endif
+}
+
+/**
+ * @brief Sets a new thread lock.
+ *
+ * The caller must not be the owner of the default thread lock.  The caller
+ * must be the owner of the new lock.
+ *
+ * @param[in] the_thread The thread.
+ * @param[in] new_lock The new thread lock.
+ */
+RTEMS_INLINE_ROUTINE void _Thread_Lock_set(
+  Thread_Control   *the_thread,
+  ISR_lock_Control *new_lock
+)
+{
+#if defined(RTEMS_SMP)
+  ISR_lock_Control *lock;
+  ISR_lock_Context  lock_context;
+
+  lock = _Thread_Lock_acquire( the_thread, &lock_context );
+  _Thread_Lock_set_unprotected( the_thread, new_lock );
+  _Thread_Lock_release( lock, &lock_context );
+#else
+  (void) the_thread;
+  (void) new_lock;
+#endif
+}
+
+/**
+ * @brief Restores the default thread lock.
+ *
+ * The caller must be the owner of the current thread lock.
+ *
+ * @param[in] the_thread The thread.
+ */
+RTEMS_INLINE_ROUTINE void _Thread_Lock_restore_default(
+  Thread_Control *the_thread
+)
+{
+  _Atomic_Fence( ATOMIC_ORDER_RELEASE );
+
+  _Thread_Lock_set_unprotected( the_thread, &the_thread->Lock.Default );
+}
+
 void _Thread_Priority_change_do_nothing(
   Thread_Control   *the_thread,
   Priority_Control  new_priority,
diff --git a/cpukit/score/src/threadchangepriority.c b/cpukit/score/src/threadchangepriority.c
index dea671d..2baa9d2 100644
--- a/cpukit/score/src/threadchangepriority.c
+++ b/cpukit/score/src/threadchangepriority.c
@@ -29,17 +29,20 @@ void _Thread_Change_priority(
   bool              prepend_it
 )
 {
-  ISR_Level level;
+  ISR_lock_Context  lock_context;
+  ISR_lock_Control *lock;
 
-  _ISR_Disable( level );
+  lock = _Thread_Lock_acquire( the_thread, &lock_context );
 
   /*
    *  Do not bother recomputing all the priority related information if
    *  we are not REALLY changing priority.
    */
   if ( the_thread->current_priority != new_priority ) {
-    uint32_t my_generation = the_thread->Priority.generation + 1;
+    uint32_t  my_generation;
+    ISR_Level level;
 
+    my_generation = the_thread->Priority.generation + 1;
     the_thread->current_priority = new_priority;
     the_thread->Priority.generation = my_generation;
 
@@ -49,7 +52,9 @@ void _Thread_Change_priority(
       the_thread->Priority.change_handler_context
     );
 
-    _ISR_Flash( level );
+    _Thread_Lock_release( lock, &lock_context );
+
+    _ISR_Disable( level );
 
     if ( the_thread->Priority.generation == my_generation ) {
       if ( _States_Is_ready( the_thread->current_state ) ) {
@@ -62,7 +67,9 @@ void _Thread_Change_priority(
         _Scheduler_Update_priority( the_thread, new_priority );
       }
     }
-  }
 
-  _ISR_Enable( level );
+    _ISR_Enable( level );
+  } else {
+    _Thread_Lock_release( lock, &lock_context );
+  }
 }
diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c
index b0066cd..27c3f06 100644
--- a/cpukit/score/src/threadinitialize.c
+++ b/cpukit/score/src/threadinitialize.c
@@ -196,6 +196,9 @@ bool _Thread_Initialize(
   the_thread->Scheduler.own_node = the_thread->Scheduler.node;
   _Resource_Node_initialize( &the_thread->Resource_node );
   _CPU_Context_Set_is_executing( &the_thread->Registers, false );
+  the_thread->Lock.current = &the_thread->Lock.Default;
+  _ISR_lock_Initialize( &the_thread->Lock.Default, "Thread Lock Default");
+  _Atomic_Init_uint(&the_thread->Lock.generation, 0);
 #endif
 
   _Thread_Debug_set_real_processor( the_thread, cpu );
diff --git a/cpukit/score/src/threadrestart.c b/cpukit/score/src/threadrestart.c
index 10d05f1..e759b5b 100644
--- a/cpukit/score/src/threadrestart.c
+++ b/cpukit/score/src/threadrestart.c
@@ -98,6 +98,10 @@ static void _Thread_Free( Thread_Control *the_thread )
 
   _Workspace_Free( the_thread->Start.tls_area );
 
+#if defined(RTEMS_SMP)
+  _ISR_lock_Destroy( &the_thread->Lock.Default );
+#endif
+
   _Objects_Free(
     _Objects_Get_information_id( the_thread->Object.id ),
     &the_thread->Object
-- 
1.8.4.5




More information about the devel mailing list