[PATCH 06/32] score: Add Thread_Change_life()

Sebastian Huber sebastian.huber at embedded-brains.de
Wed May 18 09:20:25 UTC 2016


Add _Thread_Change_life_locked() as a general function to alter the
thread life state.  Use it to implement _Thread_Set_life_protection() as
a first step.

Update #2555.
Update #2626.
---
 cpukit/libcsupport/src/privateenv.c           | 10 +--
 cpukit/score/include/rtems/score/apimutex.h   |  2 +-
 cpukit/score/include/rtems/score/mrspimpl.h   |  6 +-
 cpukit/score/include/rtems/score/threadimpl.h |  6 +-
 cpukit/score/src/apimutexlock.c               | 10 +--
 cpukit/score/src/apimutexunlock.c             | 11 ++--
 cpukit/score/src/threadrestart.c              | 95 ++++++++++++++++-----------
 testsuites/smptests/smpthreadlife01/init.c    |  2 +-
 testsuites/sptests/spthreadlife01/init.c      | 15 +++--
 9 files changed, 90 insertions(+), 67 deletions(-)

diff --git a/cpukit/libcsupport/src/privateenv.c b/cpukit/libcsupport/src/privateenv.c
index 29821e4..bf6036a 100644
--- a/cpukit/libcsupport/src/privateenv.c
+++ b/cpukit/libcsupport/src/privateenv.c
@@ -57,7 +57,8 @@ rtems_status_code rtems_libio_set_private_env(void)
   bool uses_global_env = old_env == &rtems_global_user_env;
 
   if (uses_global_env) {
-    bool life_protection = _Thread_Set_life_protection(true);
+    Thread_Life_state life_state =
+      _Thread_Set_life_protection(THREAD_LIFE_PROTECTED);
     rtems_user_env_t *new_env = calloc(1, sizeof(*new_env));
 
     if (new_env != NULL) {
@@ -92,7 +93,7 @@ rtems_status_code rtems_libio_set_private_env(void)
       sc = RTEMS_NO_MEMORY;
     }
 
-    _Thread_Set_life_protection(life_protection);
+    _Thread_Set_life_protection(life_state);
   }
 
   return sc;
@@ -104,11 +105,12 @@ void rtems_libio_use_global_env(void)
   bool uses_private_env = env != &rtems_global_user_env;
 
   if (uses_private_env) {
-    bool life_protection = _Thread_Set_life_protection(true);
+    Thread_Life_state life_state =
+      _Thread_Set_life_protection(THREAD_LIFE_PROTECTED);
 
     rtems_libio_free_user_env(env);
     pthread_setspecific(rtems_current_user_env_key, NULL);
 
-    _Thread_Set_life_protection(life_protection);
+    _Thread_Set_life_protection(life_state);
   }
 }
diff --git a/cpukit/score/include/rtems/score/apimutex.h b/cpukit/score/include/rtems/score/apimutex.h
index 86561aa..1a4b1ee 100644
--- a/cpukit/score/include/rtems/score/apimutex.h
+++ b/cpukit/score/include/rtems/score/apimutex.h
@@ -52,7 +52,7 @@ typedef struct {
    * @brief The thread life protection state before the outer-most mutex
    * obtain.
    */
-  bool previous_thread_life_protection;
+  Thread_Life_state previous_thread_life_state;
 } API_Mutex_Control;
 
 /**
diff --git a/cpukit/score/include/rtems/score/mrspimpl.h b/cpukit/score/include/rtems/score/mrspimpl.h
index 1be3202..f2570eb 100644
--- a/cpukit/score/include/rtems/score/mrspimpl.h
+++ b/cpukit/score/include/rtems/score/mrspimpl.h
@@ -218,7 +218,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
 {
   MRSP_Status status;
   MRSP_Rival rival;
-  bool initial_life_protection;
+  Thread_Life_state life_state;
   Per_CPU_Control *cpu_self;
   ISR_lock_Context giant_lock_context;
   ISR_Level level;
@@ -256,7 +256,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
     _ISR_Enable_without_giant( level );
   }
 
-  initial_life_protection = _Thread_Set_life_protection( true );
+  life_state = _Thread_Set_life_protection( THREAD_LIFE_PROTECTED );
   _Thread_Dispatch_enable( cpu_self );
 
   _Assert( _Debug_Is_thread_dispatching_allowed() );
@@ -266,7 +266,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
     status = rival.status;
   } while ( status == MRSP_WAIT_FOR_OWNERSHIP );
 
-  _Thread_Set_life_protection( initial_life_protection );
+  _Thread_Set_life_protection( life_state );
 
   if ( timeout > 0 ) {
     _ISR_Disable_without_giant( level );
diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h
index be2095e..e68f119 100644
--- a/cpukit/score/include/rtems/score/threadimpl.h
+++ b/cpukit/score/include/rtems/score/threadimpl.h
@@ -198,7 +198,7 @@ bool _Thread_Restart(
 
 void _Thread_Yield( Thread_Control *executing );
 
-bool _Thread_Set_life_protection( bool protect );
+Thread_Life_state _Thread_Set_life_protection( Thread_Life_state state );
 
 /**
  * @brief Kills all zombie threads in the system.
@@ -934,11 +934,11 @@ RTEMS_INLINE_ROUTINE bool _Thread_Is_life_terminating(
   return ( life_state & THREAD_LIFE_TERMINATING ) != 0;
 }
 
-RTEMS_INLINE_ROUTINE bool _Thread_Is_life_protected(
+RTEMS_INLINE_ROUTINE bool _Thread_Is_life_change_allowed(
   Thread_Life_state life_state
 )
 {
-  return ( life_state & THREAD_LIFE_PROTECTED ) != 0;
+  return ( life_state & THREAD_LIFE_PROTECTED ) == 0;
 }
 
 RTEMS_INLINE_ROUTINE bool _Thread_Is_life_changing(
diff --git a/cpukit/score/src/apimutexlock.c b/cpukit/score/src/apimutexlock.c
index 2e36518..79729d4 100644
--- a/cpukit/score/src/apimutexlock.c
+++ b/cpukit/score/src/apimutexlock.c
@@ -25,10 +25,11 @@
 
 void _API_Mutex_Lock( API_Mutex_Control *the_mutex )
 {
-  bool previous_thread_life_protection;
-  ISR_lock_Context lock_context;
+  Thread_Life_state previous_thread_life_state;
+  ISR_lock_Context  lock_context;
 
-  previous_thread_life_protection = _Thread_Set_life_protection( true );
+  previous_thread_life_state =
+    _Thread_Set_life_protection( THREAD_LIFE_PROTECTED );
 
   _ISR_lock_ISR_disable( &lock_context );
 
@@ -41,7 +42,6 @@ void _API_Mutex_Lock( API_Mutex_Control *the_mutex )
   );
 
   if ( the_mutex->Mutex.nest_count == 1 ) {
-    the_mutex->previous_thread_life_protection =
-      previous_thread_life_protection;
+    the_mutex->previous_thread_life_state = previous_thread_life_state;
   }
 }
diff --git a/cpukit/score/src/apimutexunlock.c b/cpukit/score/src/apimutexunlock.c
index 3545377..e129dd2 100644
--- a/cpukit/score/src/apimutexunlock.c
+++ b/cpukit/score/src/apimutexunlock.c
@@ -24,12 +24,11 @@
 
 void _API_Mutex_Unlock( API_Mutex_Control *the_mutex )
 {
-  ISR_lock_Context lock_context;
-  bool             previous_thread_life_protection;
-  bool             restore_thread_life_protection;
+  ISR_lock_Context  lock_context;
+  Thread_Life_state previous_thread_life_state;
+  bool              restore_thread_life_protection;
 
-  previous_thread_life_protection =
-    the_mutex->previous_thread_life_protection;
+  previous_thread_life_state = the_mutex->previous_thread_life_state;
   restore_thread_life_protection = the_mutex->Mutex.nest_count == 1;
 
   _ISR_lock_ISR_disable( &lock_context );
@@ -41,6 +40,6 @@ void _API_Mutex_Unlock( API_Mutex_Control *the_mutex )
   );
 
   if ( restore_thread_life_protection ) {
-    _Thread_Set_life_protection( previous_thread_life_protection );
+    _Thread_Set_life_protection( previous_thread_life_state );
   }
 }
diff --git a/cpukit/score/src/threadrestart.c b/cpukit/score/src/threadrestart.c
index 9642370..1d131d4 100644
--- a/cpukit/score/src/threadrestart.c
+++ b/cpukit/score/src/threadrestart.c
@@ -9,7 +9,7 @@
  *  COPYRIGHT (c) 1989-1999.
  *  On-Line Applications Research Corporation (OAR).
  *
- *  Copyright (c) 2014 embedded brains GmbH.
+ *  Copyright (c) 2014, 2016 embedded brains GmbH.
  *
  *  The license and distribution terms for this file may be
  *  found in the file LICENSE in this distribution or at
@@ -213,6 +213,42 @@ static void _Thread_Start_life_change_for_executing(
   _Thread_Add_life_change_action( executing );
 }
 
+static Thread_Life_state _Thread_Change_life_locked(
+  Thread_Control    *the_thread,
+  Thread_Life_state  clear,
+  Thread_Life_state  set,
+  Thread_Life_state  ignore
+)
+{
+  Thread_Life_state previous;
+  Thread_Life_state state;
+
+  previous = the_thread->Life.state;
+  state = previous;
+  state &= ~clear;
+  state |= set;
+  the_thread->Life.state = state;
+
+  state &= ~ignore;
+
+  if (
+    _Thread_Is_life_change_allowed( state )
+      && _Thread_Is_life_changing( state )
+  ) {
+    the_thread->is_preemptible   = the_thread->Start.is_preemptible;
+    the_thread->budget_algorithm = the_thread->Start.budget_algorithm;
+    the_thread->budget_callout   = the_thread->Start.budget_callout;
+
+    _Thread_Add_post_switch_action(
+      the_thread,
+      &the_thread->Life.Action,
+      _Thread_Life_action_handler
+    );
+  }
+
+  return previous;
+}
+
 void _Thread_Life_action_handler(
   Thread_Control   *executing,
   Thread_Action    *action,
@@ -393,52 +429,33 @@ bool _Thread_Restart(
   return false;
 }
 
-bool _Thread_Set_life_protection( bool protect )
+static Thread_Life_state _Thread_Change_life(
+  Thread_Life_state clear,
+  Thread_Life_state set,
+  Thread_Life_state ignore
+)
 {
-  bool               previous_life_protection;
   ISR_lock_Context   lock_context;
   Thread_Control    *executing;
-  Thread_Life_state  previous_life_state;
+  Per_CPU_Control   *cpu_self;
+  Thread_Life_state  previous;
 
   executing = _Thread_State_acquire_for_executing( &lock_context );
 
-  previous_life_state = executing->Life.state;
-  previous_life_protection = _Thread_Is_life_protected( previous_life_state );
-
-  if ( protect ) {
-    executing->Life.state = previous_life_state | THREAD_LIFE_PROTECTED;
-  } else {
-    executing->Life.state = previous_life_state & ~THREAD_LIFE_PROTECTED;
-  }
+  previous = _Thread_Change_life_locked( executing, clear, set, ignore );
 
+  cpu_self = _Thread_Dispatch_disable_critical( &lock_context );
   _Thread_State_release( executing, &lock_context );
+  _Thread_Dispatch_enable( cpu_self );
 
-#if defined(RTEMS_SMP)
-  /*
-   * On SMP configurations it is possible that a life change of an executing
-   * thread is requested, but this thread didn't notice it yet.  The life
-   * change is first marked in the life state field and then all scheduling and
-   * other thread state updates are performed.  The last step is to issues an
-   * inter-processor interrupt if necessary.  Since this takes some time we
-   * have to synchronize here.
-   */
-  if (
-    !_Thread_Is_life_protected( previous_life_state )
-      && _Thread_Is_life_changing( previous_life_state )
-  ) {
-    _Thread_Disable_dispatch();
-    _Thread_Enable_dispatch();
-  }
-#endif
-
-  if (
-    !protect
-      && _Thread_Is_life_changing( previous_life_state )
-  ) {
-    _Thread_Disable_dispatch();
-    _Thread_Start_life_change_for_executing( executing );
-    _Thread_Enable_dispatch();
-  }
+  return previous;
+}
 
-  return previous_life_protection;
+Thread_Life_state _Thread_Set_life_protection( Thread_Life_state state )
+{
+  return _Thread_Change_life(
+    THREAD_LIFE_PROTECTED,
+    state & THREAD_LIFE_PROTECTED,
+    0
+  );
 }
diff --git a/testsuites/smptests/smpthreadlife01/init.c b/testsuites/smptests/smpthreadlife01/init.c
index 4597520..bd4c88d 100644
--- a/testsuites/smptests/smpthreadlife01/init.c
+++ b/testsuites/smptests/smpthreadlife01/init.c
@@ -221,7 +221,7 @@ static void delay_ipi_task(rtems_task_argument variant)
    * We get deleted as a side effect of enabling the thread life protection or
    * later if we enable the thread dispatching.
    */
-  _Thread_Set_life_protection(true);
+  _Thread_Set_life_protection( THREAD_LIFE_PROTECTED );
 
   if (variant != 0) {
     _Thread_Enable_dispatch();
diff --git a/testsuites/sptests/spthreadlife01/init.c b/testsuites/sptests/spthreadlife01/init.c
index 6bf2d7f..7724635 100644
--- a/testsuites/sptests/spthreadlife01/init.c
+++ b/testsuites/sptests/spthreadlife01/init.c
@@ -231,7 +231,7 @@ static void worker_task(rtems_task_argument arg)
   while (true) {
     test_state state = ctx->current;
     rtems_status_code sc;
-    bool previous_thread_life_protection;
+    Thread_Life_state previous_thread_life_state;
 
     switch (state) {
       case SET_PRIO:
@@ -273,14 +273,19 @@ static void worker_task(rtems_task_argument arg)
         break;
       case SET_PROTECTION:
         _Thread_Disable_dispatch();
-        previous_thread_life_protection = _Thread_Set_life_protection(true);
-        rtems_test_assert(!previous_thread_life_protection);
+        previous_thread_life_state =
+          _Thread_Set_life_protection(THREAD_LIFE_PROTECTED);
+        rtems_test_assert(
+          (previous_thread_life_state & THREAD_LIFE_PROTECTED) == 0
+        );
         _Thread_Enable_dispatch();
         break;
       case CLEAR_PROTECTION:
         _Thread_Disable_dispatch();
-        previous_thread_life_protection = _Thread_Set_life_protection(false);
-        rtems_test_assert(previous_thread_life_protection);
+        previous_thread_life_state = _Thread_Set_life_protection(0);
+        rtems_test_assert(
+          (previous_thread_life_state & THREAD_LIFE_PROTECTED) != 0
+        );
         ctx->current = DELETE_4;
         _Thread_Enable_dispatch();
         break;
-- 
1.8.4.5




More information about the devel mailing list