[PATCH rtems v2] once.c, onceimplh.h: Make synchronization variable volatile

Joel Sherrill joel at rtems.org
Mon Nov 20 17:42:13 UTC 2023


The loop that waits for another thread to complete the once
initialization was flagged as a potential infinite loop.
This is because there was no way to break out of the loop
inside the loop.  The solution is to make the state variable
volatile which indicates it may be modified by another thread
of execution.

This was flagged by a user Coverity Scan run which apparently is
configured differently from the instance provided by Coverity to
open source projects.
---
 cpukit/include/rtems/score/onceimpl.h |  8 ++++++--
 cpukit/score/src/once.c               | 13 ++++++++++++-
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/cpukit/include/rtems/score/onceimpl.h b/cpukit/include/rtems/score/onceimpl.h
index 9552cc0a67..5c716ce40a 100644
--- a/cpukit/include/rtems/score/onceimpl.h
+++ b/cpukit/include/rtems/score/onceimpl.h
@@ -64,11 +64,15 @@ extern "C" {
  * Once_Information_Mutex.
  *
  * @param once_state The once state.
- * @param init_routine The initialization routine called if @a once_state is ONCE_STATE_INIT.
+ * @param init_routine The initialization routine called if @a once_state
+ *     is ONCE_STATE_INIT.
  *
  * @return This method always returns zero upon termination.
  */
-int _Once( unsigned char *once_state, void ( *init_routine )( void ) );
+int _Once(
+  volatile unsigned char   *once_state,
+  void                   ( *init_routine )( void )
+);
 
 /** @} */
 
diff --git a/cpukit/score/src/once.c b/cpukit/score/src/once.c
index a395197c3a..10a5c4fee6 100644
--- a/cpukit/score/src/once.c
+++ b/cpukit/score/src/once.c
@@ -75,7 +75,10 @@ static void _Once_Unlock( Thread_Life_state thread_life_state )
   _Thread_Set_life_protection( thread_life_state );
 }
 
-int _Once( unsigned char *once_state, void ( *init_routine )( void ) )
+int _Once(
+  volatile unsigned char   *once_state,
+  void                   ( *init_routine )( void )
+)
 {
   _Atomic_Fence( ATOMIC_ORDER_ACQUIRE );
 
@@ -93,6 +96,14 @@ int _Once( unsigned char *once_state, void ( *init_routine )( void ) )
       *once_state = ONCE_STATE_COMPLETE;
       rtems_condition_variable_broadcast( &_Once_Information.State );
     } else {
+      /*
+       * This is flagged as an infinite loop by at least Coverity. It is
+       * not an infinite loop because *once_state is set by another
+       * thread. This loop is used when a second thread concurrently
+       * attempts to process a once variable while it is in the process
+       * of being initialized.  The second and subsequent threads block
+       * until the broadcast above is executed.
+       */
       while ( *once_state != ONCE_STATE_COMPLETE ) {
         rtems_condition_variable_wait(
           &_Once_Information.State,
-- 
2.31.1



More information about the devel mailing list