From 03acc5915e002f0b03eee9e86212209705cca6d6 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 14 Aug 2013 10:21:41 +1000 Subject: posix: Change pthread_once to be SMP safe. Change pthread_once from using disabled pre-emption to using a pthread mutex making it SMP safe. GCC using a posix threading model uses pthread_once. The pthread mutex requires at least 1 mutex is configured so confdefs.h has been updated to account for the internal mutex. --- cpukit/posix/Makefile.am | 6 ++- cpukit/posix/include/rtems/posix/onceimpl.h | 57 +++++++++++++++++++++++++++++ cpukit/posix/preinstall.am | 4 ++ cpukit/posix/src/once.c | 49 +++++++++++++++++++++++++ cpukit/posix/src/pthreadonce.c | 50 ++++++++++++++++++++----- cpukit/sapi/include/confdefs.h | 7 ++++ cpukit/sapi/src/posixapi.c | 2 + 7 files changed, 164 insertions(+), 11 deletions(-) create mode 100644 cpukit/posix/include/rtems/posix/onceimpl.h create mode 100644 cpukit/posix/src/once.c (limited to 'cpukit') diff --git a/cpukit/posix/Makefile.am b/cpukit/posix/Makefile.am index 1b83eee090..ea6d3d983d 100644 --- a/cpukit/posix/Makefile.am +++ b/cpukit/posix/Makefile.am @@ -33,6 +33,7 @@ include_rtems_posix_HEADERS += include/rtems/posix/mqueue.h include_rtems_posix_HEADERS += include/rtems/posix/mqueueimpl.h include_rtems_posix_HEADERS += include/rtems/posix/mutex.h include_rtems_posix_HEADERS += include/rtems/posix/muteximpl.h +include_rtems_posix_HEADERS += include/rtems/posix/onceimpl.h include_rtems_posix_HEADERS += include/rtems/posix/posixapi.h include_rtems_posix_HEADERS += include/rtems/posix/priorityimpl.h include_rtems_posix_HEADERS += include/rtems/posix/psignal.h @@ -115,6 +116,9 @@ libposix_a_SOURCES += src/mutexattrdestroy.c src/mutexattrgetprioceiling.c \ src/mutexlocksupp.c src/mutexsetprioceiling.c src/mutextimedlock.c \ src/mutextranslatereturncode.c src/mutextrylock.c src/mutexunlock.c +## ONCE_C_FILES +libposix_a_SOURCES += src/once.c src/pthreadonce.c + ## PTHREAD_C_FILES libposix_a_SOURCES += src/pthreadatfork.c src/pthreadattrdestroy.c \ src/pthreadattrgetdetachstate.c src/pthreadattrgetinheritsched.c \ @@ -131,7 +135,7 @@ libposix_a_SOURCES += src/pthreadatfork.c src/pthreadattrdestroy.c \ src/pthreadexit.c src/pthreadgetcpuclockid.c \ src/pthreadgetschedparam.c \ src/pthreadinitthreads.c src/pthreadjoin.c src/pthreadkill.c \ - src/pthreadonce.c src/pthreadself.c \ + src/pthreadself.c \ src/pthreadsetschedparam.c src/pthreadsigmask.c \ src/psxpriorityisvalid.c src/psxtransschedparam.c diff --git a/cpukit/posix/include/rtems/posix/onceimpl.h b/cpukit/posix/include/rtems/posix/onceimpl.h new file mode 100644 index 0000000000..f0238107a6 --- /dev/null +++ b/cpukit/posix/include/rtems/posix/onceimpl.h @@ -0,0 +1,57 @@ +/** + * @file + * + * @brief Private Inlined Routines for POSIX Once + * + * This include file contains the static inline implementation of the private + * inlined routines for POSIX once. + */ + +/* + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * COPYRIGHT (c) 2013. + * Chris Johns + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include +#include + +#ifndef _RTEMS_POSIX_ONCEIMPL_H +#define _RTEMS_POSIX_ONCEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup POSIX_ONCE + * + * @{ + */ + +/** + * @brief Lock to allow once mutex's to be initialized. + */ +POSIX_EXTERN pthread_mutex_t _POSIX_Once_Lock; + +/** + * @brief POSIX once manager initialization. + * + * This routine performs the initialization necessary for this manager. + */ +void _POSIX_Once_Manager_initialization(void); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif +/* end of include file */ diff --git a/cpukit/posix/preinstall.am b/cpukit/posix/preinstall.am index 093a9df914..d0e238cd15 100644 --- a/cpukit/posix/preinstall.am +++ b/cpukit/posix/preinstall.am @@ -84,6 +84,10 @@ $(PROJECT_INCLUDE)/rtems/posix/muteximpl.h: include/rtems/posix/muteximpl.h $(PR $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/posix/muteximpl.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/posix/muteximpl.h +$(PROJECT_INCLUDE)/rtems/posix/onceimpl.h: include/rtems/posix/onceimpl.h $(PROJECT_INCLUDE)/rtems/posix/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/posix/onceimpl.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/posix/onceimpl.h + $(PROJECT_INCLUDE)/rtems/posix/posixapi.h: include/rtems/posix/posixapi.h $(PROJECT_INCLUDE)/rtems/posix/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/posix/posixapi.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/posix/posixapi.h diff --git a/cpukit/posix/src/once.c b/cpukit/posix/src/once.c new file mode 100644 index 0000000000..d77c3c12e3 --- /dev/null +++ b/cpukit/posix/src/once.c @@ -0,0 +1,49 @@ +/** + * @file + * + * @brief POSIX Once Manager Initialization + * @ingroup POSIX_ONCE POSIX Once Support + */ + +/* + * COPYRIGHT (c) 2013 + * Chris Johns + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include + +pthread_mutex_t _POSIX_Once_Lock; + +void _POSIX_Once_Manager_initialization(void) +{ + pthread_mutexattr_t mattr; + int r; + + _POSIX_Once_Lock = PTHREAD_MUTEX_INITIALIZER; + + r = pthread_mutexattr_init( &mattr ); + if ( r != 0 ) + rtems_fatal( RTEMS_FATAL_SOURCE_ASSERT, 0x80aa0000 | r ); + + r = pthread_mutexattr_settype( &mattr, PTHREAD_MUTEX_RECURSIVE ); + if ( r != 0 ) + rtems_fatal( RTEMS_FATAL_SOURCE_ASSERT, 0x80aa1000 | r ); + + r = pthread_mutex_init( &_POSIX_Once_Lock, &mattr ); + if ( r != 0 ) + rtems_fatal( RTEMS_FATAL_SOURCE_ASSERT, 0x80aa2000 | r ); + + pthread_mutexattr_destroy( &mattr ); +} diff --git a/cpukit/posix/src/pthreadonce.c b/cpukit/posix/src/pthreadonce.c index 0700a222c7..2b02f1e53c 100644 --- a/cpukit/posix/src/pthreadonce.c +++ b/cpukit/posix/src/pthreadonce.c @@ -25,25 +25,55 @@ #include #include -#include +#include + +#define PTHREAD_ONCE_INIT_NOT_RUN 0 +#define PTHREAD_ONCE_INIT_RUNNING 1 +#define PTHREAD_ONCE_INIT_RUN 2 int pthread_once( pthread_once_t *once_control, void (*init_routine)(void) ) { + int r = 0; + if ( !once_control || !init_routine ) return EINVAL; - if ( !once_control->init_executed ) { - rtems_mode saveMode; - rtems_task_mode(RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &saveMode); - if ( !once_control->init_executed ) { - once_control->is_initialized = true; - once_control->init_executed = true; - (*init_routine)(); + if ( once_control->is_initialized != 1 ) + return EINVAL; + + if ( once_control->init_executed != PTHREAD_ONCE_INIT_RUN ) { + r = pthread_mutex_lock( &_POSIX_Once_Lock ); + if ( r == 0 ) { + int rr; + + /* + * Getting to here means the once_control is locked so we have: + * 1. The init has not run and the state is PTHREAD_ONCE_INIT_NOT_RUN. + * 2. The init has finished and the state is PTHREAD_ONCE_INIT_RUN. + * 3. The init is being run by this thread and the state + * PTHREAD_ONCE_INIT_RUNNING so we are nesting. This is an error. + */ + + switch ( once_control->init_executed ) { + case PTHREAD_ONCE_INIT_NOT_RUN: + once_control->init_executed = PTHREAD_ONCE_INIT_RUNNING; + (*init_routine)(); + once_control->init_executed = PTHREAD_ONCE_INIT_RUN; + break; + case PTHREAD_ONCE_INIT_RUNNING: + r = EINVAL; + break; + default: + break; + } + rr = pthread_mutex_unlock( &_POSIX_Once_Lock ); + if ( r == 0 ) + r = rr; } - rtems_task_mode(saveMode, RTEMS_PREEMPT_MASK, &saveMode); } - return 0; + + return r; } diff --git a/cpukit/sapi/include/confdefs.h b/cpukit/sapi/include/confdefs.h index 50db8779af..2a3af15912 100644 --- a/cpukit/sapi/include/confdefs.h +++ b/cpukit/sapi/include/confdefs.h @@ -1694,6 +1694,11 @@ const rtems_libio_helper rtems_fs_init_helper = #include #include + /** + * POSIX Once support uses a single mutex. + */ + #define CONFIGURE_MAXIMUM_POSIX_INTERNAL_MUTEXES 1 + /** * Account for the object control structures plus the name * of the object to be duplicated. @@ -1856,6 +1861,7 @@ const rtems_libio_helper rtems_fs_init_helper = #define CONFIGURE_MEMORY_FOR_POSIX \ ( CONFIGURE_MEMORY_FOR_POSIX_MUTEXES( CONFIGURE_MAXIMUM_POSIX_MUTEXES + \ + CONFIGURE_MAXIMUM_POSIX_INTERNAL_MUTEXES + \ CONFIGURE_MAXIMUM_GO_CHANNELS + CONFIGURE_GO_INIT_MUTEXES) + \ CONFIGURE_MEMORY_FOR_POSIX_CONDITION_VARIABLES( \ CONFIGURE_MAXIMUM_POSIX_CONDITION_VARIABLES + \ @@ -2304,6 +2310,7 @@ const rtems_libio_helper rtems_fs_init_helper = CONFIGURE_MAXIMUM_POSIX_THREADS + CONFIGURE_MAXIMUM_ADA_TASKS + CONFIGURE_MAXIMUM_GOROUTINES, CONFIGURE_MAXIMUM_POSIX_MUTEXES + CONFIGURE_GNAT_MUTEXES + + CONFIGURE_MAXIMUM_POSIX_INTERNAL_MUTEXES + CONFIGURE_MAXIMUM_ADA_TASKS + CONFIGURE_MAXIMUM_FAKE_ADA_TASKS + CONFIGURE_GO_INIT_MUTEXES + CONFIGURE_MAXIMUM_GO_CHANNELS, CONFIGURE_MAXIMUM_POSIX_CONDITION_VARIABLES + diff --git a/cpukit/sapi/src/posixapi.c b/cpukit/sapi/src/posixapi.c index af9ba2cac3..2d784a1671 100644 --- a/cpukit/sapi/src/posixapi.c +++ b/cpukit/sapi/src/posixapi.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,7 @@ void _POSIX_API_Initialize(void) _POSIX_Key_Manager_initialization(); _POSIX_Mutex_Manager_initialization(); _POSIX_Message_queue_Manager_initialization(); + _POSIX_Once_Manager_initialization(); _POSIX_Semaphore_Manager_initialization(); _POSIX_Timer_Manager_initialization(); _POSIX_Barrier_Manager_initialization(); -- cgit v1.2.3