summaryrefslogtreecommitdiffstats
path: root/cpukit/score/src/once.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2019-02-12 12:19:38 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2019-02-18 07:25:58 +0100
commite4ad14cc789090290550e3aa9640e4969037e8b7 (patch)
tree94d366cf331ee1f5dc10fc4e4298a41ed878acfd /cpukit/score/src/once.c
parentlibdl/rap: Add the section alloc call after section load was split (diff)
downloadrtems-e4ad14cc789090290550e3aa9640e4969037e8b7.tar.bz2
score: Avoid some deadlocks in _Once()
Recursive usage of the same pthread_once_t results now in a deadlock. Previously, an error of EINVAL was returned. This usage scenario is invalid according to the POSIX pthread_once() specification. Close #3334.
Diffstat (limited to 'cpukit/score/src/once.c')
-rw-r--r--cpukit/score/src/once.c117
1 files changed, 74 insertions, 43 deletions
diff --git a/cpukit/score/src/once.c b/cpukit/score/src/once.c
index 5237c11878..2b2cc0e89b 100644
--- a/cpukit/score/src/once.c
+++ b/cpukit/score/src/once.c
@@ -1,68 +1,99 @@
/*
- * COPYRIGHT (c) 1989-1999.
- * On-Line Applications Research Corporation (OAR).
+ * SPDX-License-Identifier: BSD-2-Clause
*
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
+ * Copyright (C) 2019 embedded brains GmbH
+ * Copyright (C) 2019 Sebastian Huber
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
- #include "config.h"
+#include "config.h"
#endif
#include <rtems/score/onceimpl.h>
-#include <rtems/score/apimutex.h>
+#include <rtems/score/threadimpl.h>
+#include <rtems/thread.h>
+
+#define ONCE_STATE_INIT 0
-#include <errno.h>
+#define ONCE_STATE_RUNNING 1
-#define ONCE_STATE_NOT_RUN 0
-#define ONCE_STATE_RUNNING 1
#define ONCE_STATE_COMPLETE 2
+typedef struct {
+ rtems_mutex Mutex;
+ rtems_condition_variable State;
+} Once_Control;
+
+static Once_Control _Once_Information = {
+ .Mutex = RTEMS_MUTEX_INITIALIZER( "_Once" ),
+ .State = RTEMS_CONDITION_VARIABLE_INITIALIZER( "_Once" )
+};
+
int _Once( unsigned char *once_state, void ( *init_routine )( void ) )
{
- int eno = 0;
-
- if ( *once_state != ONCE_STATE_COMPLETE ) {
- _Once_Lock();
-
- /*
- * Getting to here means the once_control is locked so we have:
- * 1. The init has not run and the state is ONCE_STATE_NOT_RUN.
- * 2. The init has finished and the state is ONCE_STATE_COMPLETE (already
- * caught by the previous if).
- * 3. The init is being run by this thread and the state
- * ONCE_STATE_RUNNING so we are nesting. This is an error.
- */
-
- switch ( *once_state ) {
- case ONCE_STATE_NOT_RUN:
- *once_state = ONCE_STATE_RUNNING;
- ( *init_routine )();
- *once_state = ONCE_STATE_COMPLETE;
- break;
- case ONCE_STATE_RUNNING:
- eno = EINVAL;
- break;
- default:
- break;
+ _Atomic_Fence( ATOMIC_ORDER_ACQUIRE );
+
+ if ( RTEMS_PREDICT_FALSE( *once_state != ONCE_STATE_COMPLETE ) ) {
+ Thread_Life_state thread_life_state;
+
+ thread_life_state = _Once_Lock();
+
+ if ( *once_state == ONCE_STATE_INIT ) {
+ *once_state = ONCE_STATE_RUNNING;
+ _Once_Unlock( THREAD_LIFE_PROTECTED );
+ ( *init_routine )();
+ _Once_Lock();
+ _Atomic_Fence( ATOMIC_ORDER_RELEASE );
+ *once_state = ONCE_STATE_COMPLETE;
+ rtems_condition_variable_broadcast( &_Once_Information.State );
+ } else {
+ while ( *once_state != ONCE_STATE_COMPLETE ) {
+ rtems_condition_variable_wait(
+ &_Once_Information.State,
+ &_Once_Information.Mutex
+ );
+ }
}
- _Once_Unlock();
+ _Once_Unlock( thread_life_state );
}
- return eno;
+ return 0;
}
-static API_Mutex_Control _Once_Mutex = API_MUTEX_INITIALIZER( "_Once" );
-
-void _Once_Lock( void )
+Thread_Life_state _Once_Lock( void )
{
- _API_Mutex_Lock( &_Once_Mutex );
+ Thread_Life_state thread_life_state;
+
+ thread_life_state = _Thread_Set_life_protection( THREAD_LIFE_PROTECTED );
+ rtems_mutex_lock( &_Once_Information.Mutex );
+
+ return thread_life_state;
}
-void _Once_Unlock( void )
+void _Once_Unlock( Thread_Life_state thread_life_state )
{
- _API_Mutex_Unlock( &_Once_Mutex );
+ rtems_mutex_unlock( &_Once_Information.Mutex );
+ _Thread_Set_life_protection( thread_life_state );
}