diff --git a/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 b/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 index dee6a86f0..97e3cb1f3 100644 --- a/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 +++ b/configure/os/CONFIG_SITE.cygwin-x86.cygwin-x86 @@ -7,4 +7,5 @@ #------------------------------------------------------- # GNU_DIR used when COMMANDLINE_LIBRARY is READLINE -#GNU_DIR=C:/cygwin \ No newline at end of file +#GNU_DIR=C:/cygwin + diff --git a/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin b/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin index b28b04f64..139597f9c 100644 --- a/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin +++ b/configure/os/CONFIG_SITE.win32-x86-cygwin.win32-x86-cygwin @@ -1,3 +1,2 @@ - diff --git a/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw b/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw index 771a4ba87..259d1e0c8 100644 --- a/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw +++ b/configure/os/CONFIG_SITE.win32-x86-mingw.win32-x86-mingw @@ -14,3 +14,4 @@ #AR = $(CMPLR_PREFIX)ar -rc #LD = $(CMPLR_PREFIX)ld -r #RANLIB = $(CMPLR_PREFIX)ranlib + diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h index 8b06bd7bb..7e961386a 100644 --- a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -50,6 +50,8 @@ && GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T ) \ || GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER +#define OSD_ATOMIC_INLINE_DEFINITION + #ifdef __cplusplus extern "C" { #endif @@ -120,11 +122,6 @@ OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * #endif #else /* if GCC_ATOMIC_INTRINSICS_AVAIL */ - -# if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER && __i386 - /* 386 hardware is probably rare today even in embedded systems */ -# warning "this code will run much faster if specifying i486 or better" -# endif /* * not available as gcc intrinsics so we diff --git a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h index 4923664e7..fa3ba8a81 100644 --- a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h @@ -66,6 +66,8 @@ # error unexpected target architecture, msvc version of epicsAtomicCD.h #endif +#define OSD_ATOMIC_INLINE_DEFINITION + /* * The windows doc appears to recommend defining InterlockedExchange * to be _InterlockedExchange to cause it to be an intrinsic, but that diff --git a/src/libCom/osi/epicsAtomic.h b/src/libCom/osi/epicsAtomic.h index 37313a5bb..aa389ea2f 100644 --- a/src/libCom/osi/epicsAtomic.h +++ b/src/libCom/osi/epicsAtomic.h @@ -80,25 +80,6 @@ epicsShareFunc EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTa EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ); -/* - * the following are, never inline and always synchronized by a global - * mutual exclusion lock, implementations of the epicsAtomicXxxx interface - * which may used to implement the epicsAtomicXxxx functions when - * more efficent primitives aren't available - */ -epicsShareFunc size_t epicsLockedIncrSizeT ( size_t * pTarget ); -epicsShareFunc size_t epicsLockedDecrSizeT ( size_t * pTarget ); -epicsShareFunc void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal ); -epicsShareFunc void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal ); -epicsShareFunc void epicsLockedSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ); -epicsShareFunc size_t epicsLockedGetSizeT ( const size_t * pTarget ); -epicsShareFunc unsigned epicsLockedGetUIntT ( const unsigned * pTarget ); -epicsShareFunc EpicsAtomicPtrT epicsLockedGetPtrT ( const EpicsAtomicPtrT * pTarget ); -epicsShareFunc unsigned epicsLockedCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldval, unsigned newval ); -epicsShareFunc EpicsAtomicPtrT epicsLockedCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ); - #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/src/libCom/osi/epicsAtomicGuard.h b/src/libCom/osi/epicsAtomicGuard.h new file mode 100644 index 000000000..7e5cf5334 --- /dev/null +++ b/src/libCom/osi/epicsAtomicGuard.h @@ -0,0 +1,54 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#ifndef epicsAtomicGuard_h +#define epicsAtomicGuard_h + +// +// This header file is intended only for use with the epicsAtomicLocked +// header file. The intent is that an OS specific implementation of +// epicsAtomicOSD.cpp might first include this file, next implement +// AtomicGuard depending on os specific capabilities, and finally include +// the epicsAtomicLocked header file to define the various epicsAtomicXxxx +// functions. +// +// The AtomicGuard class is defined in a seperate header file +// from the epicsAtomicLocked header for two reasons. +// o First, it must be possible to have an inline definition of the +// AtomicGuard member functions, and that isnt possible if the +// epicsAtomicXxxx function definitions in the epicsAtomicLocked +// header file have already been seen by the translation unit. +// o Second, we need to enforce a uniform interface for all definitions +// of the the AtomicGuard constructor and destructor member functions +// requiring that no exception are thrown. This is because the +// epicsAtomicXxxx functions in the epicsAtomicLocked header file are +// directly callable by C code. +// +// The epicsAtomicXxxx functions in the epicsAtomicLocked do not pass +// any parameters to the AtomicGuard constructor, and therefore the lock +// used by AtomicGuard is restricted to be a global lock for the entire +// multithreaded executable. Therefore, AtomicGuard will typically +// reference some translation unit scope limited global variable in +// the anonymous namespace for implementation of the locking primitive. +// + +namespace { + struct AtomicGuard { + AtomicGuard () throw (); + ~AtomicGuard () throw (); + }; +} // end of anonymous namespace + +#endif // ifndef epicsAtomicGuard_h \ No newline at end of file diff --git a/src/libCom/osi/epicsAtomicLocked.h b/src/libCom/osi/epicsAtomicLocked.h index 64cad6351..4707d66f9 100644 --- a/src/libCom/osi/epicsAtomicLocked.h +++ b/src/libCom/osi/epicsAtomicLocked.h @@ -11,86 +11,108 @@ * Author Jeffrey O. Hill * johill@lanl.gov */ + +// +// The epicsAtomicXxxxx functions herein are implemented with C++ but directly +// callable by C code, and therefore they must not be instantiated inline. +// Therefore, this isnt a traditional header file because it has function +// definitions that are not inline, and must therefore be included by only +// one module in the executable - typically this is the epicsAtomicOSD +// c++ source file. These out-of-line function definitions are placed in a +// header file so that there is potential code reuse when instantiating for +// a specific OS. An alternative option would have been to place these +// function definitions in a OS type conditionally compiled source file +// but this wasnt done because I suspect that selecting the posix version +// would require a proliferation of "SRCS_XXXX += xxx.cpp" in the libCom +// Makefile for every variety of Unix (a maintenance headache when new +// varieties of UNIX are configured). +// +// Aee also the comments in epicsAtomicGuard header. +// #ifndef epicsAtomicLocked_h #define epicsAtomicLocked_h -#if defined ( OSD_ATOMIC_INLINE ) +#ifndef __cplusplus +# error epicsAtomicLocked.h is intended only for use only by C++ code +#endif + +#include "epicsAtomic.h" // always cross check the function prototypes +#include "epicsAtomicGuard.h" -#ifdef __cplusplus extern "C" { -#endif /* __cplusplus */ -OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) +size_t epicsAtomicIncrSizeT ( size_t * pTarget ) { - return epicsLockedIncrSizeT ( pTarget ); + AtomicGuard atomicGuard; + return ++(*pTarget); } -OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ) +size_t epicsAtomicDecrSizeT ( size_t * pTarget ) { - return epicsLockedDecrSizeT ( pTarget ); + AtomicGuard atomicGuard; + return --(*pTarget); } -OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) +void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal ) { - epicsLockedSetSizeT ( pTarget, newVal ); + AtomicGuard atomicGuard; + *pTarget = newVal; } -OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) +void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) { - return epicsLockedGetSizeT ( pTarget ); + AtomicGuard atomicGuard; + *pTarget = newVal; } -OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) { - return epicsLockedGetUIntT ( pTarget ); + AtomicGuard atomicGuard; + *pTarget = newVal; } -OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) +unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) { - epicsLockedSetUIntT ( pTarget, newVal ); + AtomicGuard atomicGuard; + return *pTarget; } -OSD_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newVal ) +size_t epicsAtomicGetSizeT ( const size_t * pTarget ) { - epicsLockedSetPtrT ( pTarget, newVal ); + AtomicGuard atomicGuard; + return *pTarget; } -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) +EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ) { - return epicsLockedGetPtrT ( pTarget ); + AtomicGuard atomicGuard; + return *pTarget; } -OSD_ATOMIC_INLINE unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, - unsigned oldVal, unsigned newVal ) +unsigned epicsAtomicCmpAndSwapUIntT ( unsigned * pTarget, + unsigned oldval, unsigned newval ) { - return epicsLockedCmpAndSwapUIntT ( pTarget, oldVal, newVal ); + AtomicGuard atomicGuard; + const unsigned cur = *pTarget; + if ( cur == oldval ) { + *pTarget = newval; + } + return cur; } -OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, - EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal ) +EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, + EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval ) { - return epicsLockedCmpAndSwapPtrT ( pTarget, oldVal, newVal ); + AtomicGuard atomicGuard; + const EpicsAtomicPtrT cur = *pTarget; + if ( cur == oldval ) { + *pTarget = newval; + } + return cur; } -#ifdef __cplusplus -} /* end of extern "C" */ -#endif /* __cplusplus */ - -#else /* if defined ( OSD_ATOMIC_INLINE ) */ - -# define epicsAtomicIncrSizeT epicsLockedIncrSizeT -# define epicsAtomicDecrSizeT epicsLockedDecrSizeT -# define epicsAtomicSetSizeT epicsLockedSetSizeT -# define epicsAtomicSetUIntT epicsLockedSetUIntT -# define epicsAtomicSetPtrT epicsLockedSetPtrT -# define epicsAtomicGetSizeT epicsLockedGetSizeT -# define epicsAtomicGetUIntT epicsLockedGetUIntT -# define epicsAtomicGetPtrT epicsLockedGetPtrT -# define epicsAtomicCmpAndSwapUIntT epicsLockedCmpAndSwapUIntT -# define epicsAtomicCmpAndSwapPtrT epicsLockedCmpAndSwapPtrT - -#endif /* if defined ( OSD_ATOMIC_INLINE ) */ +} // end of extern "C" #endif /* epicsAtomicLocked_h */ diff --git a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h index 3b3ab6942..bcf48facd 100644 --- a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h @@ -30,6 +30,8 @@ extern "C" { #endif /* __cplusplus */ +#define OSD_ATOMIC_INLINE_DEFINITION + /* * mingw doesnt currently provide MemoryBarrier * (this is mostly for testing purposes as the gnu diff --git a/src/libCom/osi/os/default/epicsAtomicOSD.cpp b/src/libCom/osi/os/default/epicsAtomicOSD.cpp new file mode 100644 index 000000000..ecb1ad7c9 --- /dev/null +++ b/src/libCom/osi/os/default/epicsAtomicOSD.cpp @@ -0,0 +1,26 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + */ + +#define epicsExportSharedSymbols +#include "epicsAtomic.h" + +// +// We need a default epicsAtopmicOSD.cpp which is empty for use when +// a compiler or inline OS specific implementation is provided. See +// "osi/os/posix/epicsAtomicOSD.cpp" for an example OS specific generic +// out-of-line implementation based on a mutex lock. +// +#if ! defined ( OSD_ATOMIC_INLINE_DEFINITION ) +# error the epicsAtomicXxxxx functions definitions are misssing +#endif + diff --git a/src/libCom/osi/os/default/epicsAtomicOSD.h b/src/libCom/osi/os/default/epicsAtomicOSD.h index 0b250495b..bf09ae083 100644 --- a/src/libCom/osi/os/default/epicsAtomicOSD.h +++ b/src/libCom/osi/os/default/epicsAtomicOSD.h @@ -16,6 +16,4 @@ #ifndef epicsAtomicOSD_h #define epicsAtomicOSD_h -#include "epicsAtomicLocked.h" - #endif /* epicsAtomicOSD_h */ diff --git a/src/libCom/osi/os/posix/epicsAtomicOSD.cpp b/src/libCom/osi/os/posix/epicsAtomicOSD.cpp new file mode 100644 index 000000000..e6cf40d22 --- /dev/null +++ b/src/libCom/osi/os/posix/epicsAtomicOSD.cpp @@ -0,0 +1,71 @@ + +/*************************************************************************\ +* Copyright (c) 2011 LANS LLC, as Operator of +* Los Alamos National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Author Jeffrey O. Hill + * johill@lanl.gov + * + * Provide a global mutex version of AtomicGuard on POSIX + * systems for when we dont have more efficent compiler or + * OS primitives intriniscs to use instead. + * + * We implement this mutex-based AtomicGuard primitive directly + * upon the standalone POSIX pthread library so that the epicsAtomic + * library can be used to implement other primitives such + * epicsThreadOnce. + * + * We use a static initialized pthread mutex to minimize code + * size, and are also optimistic that this can be more efficent + * than pthread_once. + */ + +#include + +#define epicsExportSharedSymbols +#include "epicsAtomic.h" + +// If we have an inline implementation then implement +// nothing that conflicts here +#if ! defined ( OSD_ATOMIC_INLINE_DEFINITION ) + +// get the interface for class AtomicGuard +#include "epicsAtomicGuard.h" + +namespace { + +// a statically initialized mutex doesnt need to be destroyed +static pthread_mutex_t AtomicGuard :: mutex = PTHREAD_MUTEX_INITIALIZER; + +inline AtomicGuard :: AtomicGuard () throw () +{ + unsigned countDown = 1000u; + while ( true ) { + status = pthread_mutex_lock ( & mutex ); + if ( status != EINTR ) break; + static const useconds_t retryDelayUSec = 100000; + usleep ( retryDelayUSec ); + countDown--; + assert ( countDown ); + } + assert ( status == 0 ); +} + +inline AtomicGuard :: ~AtomicGuard () throw () +{ + const int status = pthread_mutex_unlock ( & mutex ); + assert ( status == 0 ); +} + +} // end of namespace anonymous + +// Define the epicsAtomicXxxx functions out-of-line using this +// implementation of AtomicGuard. Note that this isnt a traditional +// c++ header file. +#include "epicsAtomicLocked.h" + +#endif // if ! defined ( #define OSD_ATOMIC_INLINE_DEFINITION ) diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index 542997ccf..48c95824a 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -29,6 +29,8 @@ #define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */ #include +#define OSD_ATOMIC_INLINE_DEFINITION + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -97,10 +99,6 @@ OSD_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * p } /* end of extern "C" */ #endif /* __cplusplus */ -#else /* ifdef __SunOS_5_10 */ - -#include "epicsAtomicLocked.h" - #endif /* ifdef __SunOS_5_10 */ #endif /* if defined ( OSD_ATOMIC_INLINE ) */ diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index e71f6d9b6..b46c66436 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -28,6 +28,8 @@ #include #include + +#define OSD_ATOMIC_INLINE_DEFINITION #ifdef __cplusplus extern "C" {