o merged in changes from the "compiler specific build" branch

o changed implementation of default mutex locked version to be POSIX specific 
so we can use a static pthread mutex which is more efficent
This commit is contained in:
Jeff Hill
2011-08-19 13:48:03 -06:00
committed by Andrew Johnson
parent 1696c5ea72
commit 8a8ba04405
14 changed files with 229 additions and 75 deletions

View File

@@ -7,4 +7,5 @@
#-------------------------------------------------------
# GNU_DIR used when COMMANDLINE_LIBRARY is READLINE
#GNU_DIR=C:/cygwin
#GNU_DIR=C:/cygwin

View File

@@ -14,3 +14,4 @@
#AR = $(CMPLR_PREFIX)ar -rc
#LD = $(CMPLR_PREFIX)ld -r
#RANLIB = $(CMPLR_PREFIX)ranlib

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -16,6 +16,4 @@
#ifndef epicsAtomicOSD_h
#define epicsAtomicOSD_h
#include "epicsAtomicLocked.h"
#endif /* epicsAtomicOSD_h */

View File

@@ -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 <unistd.h>
#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 )

View File

@@ -29,6 +29,8 @@
#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */
#include <stdint.h>
#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 ) */

View File

@@ -28,6 +28,8 @@
#include <limits.h>
#include <vxAtomicLib.h>
#define OSD_ATOMIC_INLINE_DEFINITION
#ifdef __cplusplus
extern "C" {