Merged the rebased-atomics branch.

There are still quite a lot of warnings that need cleaning
up when compiling epicsAtomicTest.cpp on a 64-bit system.
This commit is contained in:
Andrew Johnson
2011-09-09 18:09:48 -05:00
23 changed files with 2514 additions and 18 deletions

View File

@@ -410,7 +410,7 @@ $(INSTALL_INCLUDE)/% : %
$(INSTALL_INCLUDE)/os/$(OS_CLASS)/% : %
$(ECHO) "Installing OS dependent include file $@"
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
$(INSTALL_INCLUDE)/compiler/$(CMPLR_CLASS)/% : %
$(ECHO) "Installing compiler dependent include file $@"
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)

View File

@@ -124,7 +124,7 @@ OPT_CXXFLAGS_YES = /Ox /GL
# /D_CRTDBG_MAP_ALLOC
# /RTCsu catch bugs occurring only in optimized code
# /DEPICS_FREELIST_DEBUG good for detecting mem mrg bugs
OPT_CXXFLAGS_NO = /RTCsu /Zi
OPT_CXXFLAGS_NO = /RTCsu /Zi
# specify object file name and location
OBJ_CXXFLAG = /Fo

View File

@@ -88,15 +88,18 @@
as processes on the host platform.</P>
<P><B>vxWorks</B><BR>
You must have vxWorks installed if any of your target systems are
vxWorks systems. This provides the cross-compiler and header files
needed to build for these target systems. The absolute path to and version
number of the vxWorks installation is normally specified in the
base/configure/os/CONFIG_SITE.Common.vxWorksCommon file. Consult the EPICS web
pages about <a href="http://www.aps.anl.gov/epics/base/tornado.php">vxWorks
5.x</a> and <a href="http://www.aps.anl.gov/epics/base/vxWorks6.php">vxWorks
6.x</a> and the vxWorks documentation for information about configuring your
vxWorks operating system for use with EPICS.</P>
You must have vxWorks 5.5.x or 6.x installed if any of your target systems are
vxWorks systems; the C++ compiler for vxWorks 5.4 is now too old to support.
The vxWorks installation provides the cross-compiler and header files needed to
build for these targets. The absolute path to and the version number of the
vxWorks installation must be set in the
base/configure/os/CONFIG_SITE.Common.vxWorksCommon file or in one of its
target-specific overrides.</P>
<P>Consult the <a href="http://www.aps.anl.gov/epics/base/tornado.php">vxWorks
5.x</a> or <a href="http://www.aps.anl.gov/epics/base/vxWorks6.php">vxWorks
6.x</a> EPICS web pages about and the vxWorks documentation for information
about configuring your vxWorks operating system for use with EPICS.</P>
<P><B>RTEMS</B><BR>
For RTEMS targets, you need RTEMS core and toolset version 4.9.2 or later.</P>

View File

@@ -44,6 +44,10 @@ INC += osiUnistd.h
INC += osiWireFormat.h
INC += osdWireFormat.h
INC += osdWireConfig.h
INC += epicsAtomic.h
INC += epicsAtomicDefault.h
INC += epicsAtomicOSD.h
INC += epicsAtomicCD.h
INC += epicsEndian.h
INC += epicsReadline.h
INC += epicsMessageQueue.h
@@ -62,6 +66,7 @@ Com_SRCS += epicsEvent.cpp
Com_SRCS += epicsTime.cpp
Com_SRCS += epicsMessageQueue.cpp
Com_SRCS += epicsMath.cpp
Com_SRCS += epicsAtomicOSD.cpp
Com_SRCS += epicsGeneralTime.c
@@ -125,6 +130,8 @@ Com_SRCS_vxWorks += logMsgToErrlog.cpp
#This forces the vxWorks compatibility stuff to be loaded
OBJS_vxWorks = vxComLibrary
INC_WIN32 += epicsAtomicMS.h
Com_SRCS_WIN32 += epicsGetopt.c
Com_SRCS_WIN32 += setThreadName.cpp
#Com_SRCS_WIN32 += dllmain.cpp

View File

@@ -0,0 +1,31 @@
/*************************************************************************\
* 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 epicsAtomicCD_h
#define epicsAtomicCD_h
#if defined ( __cplusplus )
# define EPICS_ATOMIC_INLINE inline
#else
# define EPICS_ATOMIC_INLINE __inline__
#endif
/*
* we have an inline keyword so we can proceed
* with an os specific inline instantiation
*/
#include "epicsAtomicOSD.h"
#endif /* epicsAtomicCD_h */

View File

@@ -0,0 +1,30 @@
/*************************************************************************\
* 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 epicsAtomicCD_h
#define epicsAtomicCD_h
#if __STDC_VERSION__ >= 199901L || defined ( __cplusplus )
# define EPICS_ATOMIC_INLINE inline
/*
* We have already defined the public interface in epicsAtomic.h
* so there is nothing more to implement if there isnt an inline
* keyword available. Otherwise, if we have an inline keyword
* we will proceed with an os specific inline implementation.
*/
# include "epicsAtomicOSD.h"
#endif
#endif /* epicsAtomicCD_h */

View File

@@ -0,0 +1,172 @@
/*************************************************************************\
* 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 epicsAtomicCD_h
#define epicsAtomicCD_h
#ifndef __GNUC__
# error this header is only for use with the gnu compiler
#endif
#define EPICS_ATOMIC_INLINE __inline__
#define GCC_ATOMIC_CONCAT( A, B ) GCC_ATOMIC_CONCATR(A,B)
#define GCC_ATOMIC_CONCATR( A, B ) ( A ## B )
#define GCC_ATOMIC_INTRINSICS_AVAIL_INT_T \
GCC_ATOMIC_CONCAT ( \
__GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \
__SIZEOF_INT__ )
#define GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T \
GCC_ATOMIC_CONCAT ( \
__GCC_HAVE_SYNC_COMPARE_AND_SWAP_, \
__SIZEOF_SIZE_T__ )
#define GCC_ATOMIC_INTRINSICS_MIN_X86 \
( defined ( __i486 ) || defined ( __pentium ) || \
defined ( __pentiumpro ) || defined ( __MMX__ ) )
#define GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER \
( ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 401 )
#define GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER \
( GCC_ATOMIC_INTRINSICS_MIN_X86 && \
GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER )
#ifdef __cplusplus
extern "C" {
#endif
/*
* We are optimistic that __sync_synchronize is implemented
* in all version four gcc invarient of target. The gnu doc
* seems to say that when not supported by architecture a call
* to an external function is generated but in practice
* this isnt the case for some of the atomic intrinsics, and
* so there is an undefined symbol. So far we have not seen
* that with __sync_synchronize, but we can only guess based
* on experimental evidence.
*
* For example we know that when generating object code for
* 386 most of the atomic instrinsics are not present and
* we see undefined symbols with mingw, but we dont have
* troubles with __sync_synchronize.
*/
#if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER
#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
#define EPICS_ATOMIC_READ_MEMORY_BARRIER
EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier ()
{
__sync_synchronize ();
}
#endif
#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier ()
{
__sync_synchronize ();
}
#endif
#endif /* if GCC_ATOMIC_INTRINSICS_GCC4_OR_BETTER */
#if GCC_ATOMIC_INTRINSICS_AVAIL_INT_T \
|| GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER
#define EPICS_ATOMIC_INCR_INTT
EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
{
return __sync_add_and_fetch ( pTarget, 1 );
}
#define EPICS_ATOMIC_DECR_INTT
EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
{
return __sync_sub_and_fetch ( pTarget, 1 );
}
#define EPICS_ATOMIC_ADD_INTT
EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
{
return __sync_add_and_fetch ( pTarget, delta );
}
#define EPICS_ATOMIC_CAS_INTT
EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget,
int oldVal, int newVal )
{
return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
}
#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL_INT_T */
#if GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T \
|| GCC_ATOMIC_INTRINSICS_AVAIL_EARLIER
#define EPICS_ATOMIC_INCR_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
{
return __sync_add_and_fetch ( pTarget, 1u );
}
#define EPICS_ATOMIC_DECR_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
{
return __sync_sub_and_fetch ( pTarget, 1u );
}
#define EPICS_ATOMIC_ADD_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta )
{
return __sync_add_and_fetch ( pTarget, delta );
}
#define EPICS_ATOMIC_SUB_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
{
return __sync_sub_and_fetch ( pTarget, delta );
}
#define EPICS_ATOMIC_CAS_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget,
size_t oldVal, size_t newVal )
{
return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
}
#define EPICS_ATOMIC_CAS_PTRT
EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT (
EpicsAtomicPtrT * pTarget,
EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
{
return __sync_val_compare_and_swap ( pTarget, oldVal, newVal);
}
#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T */
#ifdef __cplusplus
} /* end of extern "C" */
#endif
/*
* if currently unavailable as gcc intrinsics we
* will try for an os specific inline solution
*/
#include "epicsAtomicOSD.h"
#endif /* epicsAtomicCD_h */

View File

@@ -0,0 +1,124 @@
/*************************************************************************\
* 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 epicsAtomicCD_h
#define epicsAtomicCD_h
#include "epicsAssert.h"
#ifndef _MSC_VER
# error this header file is only for use with with the Microsoft Compiler
#endif
#ifdef _MSC_EXTENSIONS
#include <intrin.h>
#if _MSC_VER >= 1200
# define EPICS_ATOMIC_INLINE __forceinline
#else
# define EPICS_ATOMIC_INLINE __inline
#endif
#if defined ( _M_IX86 )
# pragma warning( push )
# pragma warning( disable : 4793 )
EPICS_ATOMIC_INLINE void epicsAtomicMemoryBarrier ()
{
long fence;
__asm { xchg fence, eax }
}
# pragma warning( pop )
#elif defined ( _M_X64 )
# define MS_ATOMIC_64
# pragma intrinsic ( __faststorefence )
EPICS_ATOMIC_INLINE void epicsAtomicMemoryBarrier ()
{
__faststorefence ();
}
#elif defined ( _M_IA64 )
# define MS_ATOMIC_64
# pragma intrinsic ( __mf )
EPICS_ATOMIC_INLINE void epicsAtomicMemoryBarrier ()
{
__mf ();
}
#else
# error unexpected target architecture, msvc version of epicsAtomicCD.h
#endif
/*
* The windows doc appears to recommend defining InterlockedExchange
* to be _InterlockedExchange to cause it to be an intrinsic, but that
* creates issues when later, in a windows os specific header, we include
* windows.h. Therefore, we except some code duplication between the msvc
* csAtomic.h and win32 osdAtomic.h to avoid problems, and to keep the
* os specific windows.h header file out of the msvc cdAtomic.h
*/
#define MS_LONG long
#define MS_InterlockedExchange _InterlockedExchange
#define MS_InterlockedCompareExchange _InterlockedCompareExchange
#define MS_InterlockedIncrement _InterlockedIncrement
#define MS_InterlockedDecrement _InterlockedDecrement
#define MS_InterlockedExchange _InterlockedExchange
#define MS_InterlockedExchangeAdd _InterlockedExchangeAdd
#if defined ( MS_ATOMIC_64 )
# define MS_LONGLONG long long
# define MS_InterlockedIncrement64 _InterlockedIncrement64
# define MS_InterlockedDecrement64 _InterlockedDecrement64
# define MS_InterlockedExchange64 _InterlockedExchange64
# define MS_InterlockedExchangeAdd64 _InterlockedExchangeAdd64
# define MS_InterlockedCompareExchange64 _InterlockedCompareExchange64
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define EPICS_ATOMIC_READ_MEMORY_BARRIER
EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier ()
{
epicsAtomicMemoryBarrier ();
}
#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier ()
{
epicsAtomicMemoryBarrier ();
}
#ifdef __cplusplus
} /* end of extern "C" */
#endif /* __cplusplus */
#include "epicsAtomicMS.h"
#include "epicsAtomicDefault.h"
#else /* ifdef _MSC_EXTENSIONS */
#if defined ( __cplusplus )
# define EPICS_ATOMIC_INLINE inline
#endif
/*
* if unavailable as an intrinsic we will try
* for os specific inline solution
*/
#include "epicsAtomicOSD.h"
#endif /* ifdef _MSC_EXTENSIONS */
#endif /* epicsAtomicCD_h */

View File

@@ -0,0 +1,31 @@
/*************************************************************************\
* 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 epicsAtomicCD_h
#define epicsAtomicCD_h
#if defined ( __cplusplus )
# define EPICS_ATOMIC_INLINE inline
#else
# define EPICS_ATOMIC_INLINE __inline
#endif
/*
* we have an inline keyword so we can proceed
* with an os specific inline instantiation
*/
#include "epicsAtomicOSD.h"
#endif /* epicsAtomicCD_h */

View File

@@ -0,0 +1,236 @@
/*************************************************************************\
* 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 epicsAtomic_h
#define epicsAtomic_h
#include <stdlib.h> /* define size_t */
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void * EpicsAtomicPtrT;
/* load target into cache */
epicsShareFunc void epicsAtomicReadMemoryBarrier ();
/* push cache version of target into target */
epicsShareFunc void epicsAtomicWriteMemoryBarrier ();
/*
* lock out other smp processors from accessing the target,
* load target into cache, add one to target, flush cache
* to target, allow other smp processors to access the target,
* return new value of target as modified by this operation
*/
epicsShareFunc size_t epicsAtomicIncrSizeT ( size_t * pTarget );
epicsShareFunc int epicsAtomicIncrIntT ( int * pTarget );
/*
* lock out other smp processors from accessing the target,
* load target into cache, subtract one from target, flush cache
* to target, allow out other smp processors to access the target,
* return new value of target as modified by this operation
*/
epicsShareFunc size_t epicsAtomicDecrSizeT ( size_t * pTarget );
epicsShareFunc int epicsAtomicDecrIntT ( int * pTarget );
/*
* lock out other smp processors from accessing the target,
* load target into cache, add/sub delta to/from target, flush cache
* to target, allow other smp processors to access the target,
* return new value of target as modified by this operation
*/
epicsShareFunc size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta );
epicsShareFunc size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta );
epicsShareFunc int epicsAtomicAddIntT ( int * pTarget, int delta );
/*
* set cache version of target, flush cache to target
*/
epicsShareFunc void epicsAtomicSetSizeT ( size_t * pTarget, size_t newValue );
epicsShareFunc void epicsAtomicSetIntT ( int * pTarget, int newValue );
epicsShareFunc void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newValue );
/*
* fetch target into cache, return new value of target
*/
epicsShareFunc size_t epicsAtomicGetSizeT ( const size_t * pTarget );
epicsShareFunc int epicsAtomicGetIntT ( const int * pTarget );
epicsShareFunc EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget );
/*
* lock out other smp processors from accessing the target,
* load target into cache, if target is equal to oldVal set target
* to newVal, flush cache to target, allow other smp processors
* to access the target, return the original value stored in the
* target
*/
epicsShareFunc size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget,
size_t oldVal, size_t newVal );
epicsShareFunc int epicsAtomicCmpAndSwapIntT ( int * pTarget,
int oldVal, int newVal );
epicsShareFunc EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT (
EpicsAtomicPtrT * pTarget,
EpicsAtomicPtrT oldVal,
EpicsAtomicPtrT newVal );
#ifdef __cplusplus
} /* end of extern "C" */
#endif
/*
* options for inline compiler instrinsic or os specific
* implementations of the above function prototypes
*
* for some of the compilers we must define the
* inline functions before they get used in the c++
* inine functions below
*/
#include "epicsAtomicCD.h"
#ifdef __cplusplus
namespace epics {
namespace atomic {
/*
* overloaded c++ interface
*/
epicsShareFunc size_t increment ( size_t & v );
epicsShareFunc int increment ( int & v );
epicsShareFunc size_t decrement ( size_t & v );
epicsShareFunc int decrement ( int & v );
epicsShareFunc size_t add ( size_t & v, size_t delta );
epicsShareFunc int add ( int & v, int delta );
epicsShareFunc size_t subtract ( size_t & v, size_t delta );
epicsShareFunc int subtract ( int & v, int delta );
epicsShareFunc void set ( size_t & v , size_t newValue );
epicsShareFunc void set ( int & v, int newValue );
epicsShareFunc void set ( EpicsAtomicPtrT & v,
EpicsAtomicPtrT newValue );
epicsShareFunc size_t get ( const size_t & v );
epicsShareFunc int get ( const int & v );
epicsShareFunc EpicsAtomicPtrT get ( const EpicsAtomicPtrT & v );
epicsShareFunc size_t compareAndSwap ( size_t & v, size_t oldVal,
size_t newVal );
epicsShareFunc int compareAndSwap ( int & v, int oldVal, int newVal );
epicsShareFunc EpicsAtomicPtrT compareAndSwap ( EpicsAtomicPtrT & v,
EpicsAtomicPtrT oldVal,
EpicsAtomicPtrT newVal );
/************* incr ***************/
inline size_t increment ( size_t & v )
{
return epicsAtomicIncrSizeT ( & v );
}
inline int increment ( int & v )
{
return epicsAtomicIncrIntT ( & v );
}
/************* decr ***************/
inline size_t decrement ( size_t & v )
{
return epicsAtomicDecrSizeT ( & v );
}
inline int decrement ( int & v )
{
return epicsAtomicDecrIntT ( & v );
}
/************* add ***************/
inline size_t add ( size_t & v, size_t delta )
{
return epicsAtomicAddSizeT ( & v, delta );
}
inline int add ( int & v, int delta )
{
return epicsAtomicAddIntT ( & v, delta );
}
/************* sub ***************/
inline size_t subtract ( size_t & v, size_t delta )
{
return epicsAtomicSubSizeT ( & v, delta );
}
inline int subtract ( int & v, int delta )
{
return epicsAtomicAddIntT ( & v, -delta );
}
/************* set ***************/
inline void set ( size_t & v , size_t newValue )
{
epicsAtomicSetSizeT ( & v, newValue );
}
inline void set ( int & v, int newValue )
{
epicsAtomicSetIntT ( & v, newValue );
}
inline void set ( EpicsAtomicPtrT & v, EpicsAtomicPtrT newValue )
{
epicsAtomicSetPtrT ( & v, newValue );
}
/************* get ***************/
inline size_t get ( const size_t & v )
{
return epicsAtomicGetSizeT ( & v );
}
inline int get ( const int & v )
{
return epicsAtomicGetIntT ( & v );
}
inline EpicsAtomicPtrT get ( const EpicsAtomicPtrT & v )
{
return epicsAtomicGetPtrT ( & v );
}
/************* cas ***************/
inline size_t compareAndSwap ( size_t & v,
size_t oldVal, size_t newVal )
{
return epicsAtomicCmpAndSwapSizeT ( & v, oldVal, newVal );
}
inline int compareAndSwap ( int & v, int oldVal, int newVal )
{
return epicsAtomicCmpAndSwapIntT ( & v, oldVal, newVal );
}
inline EpicsAtomicPtrT compareAndSwap ( EpicsAtomicPtrT & v,
EpicsAtomicPtrT oldVal,
EpicsAtomicPtrT newVal )
{
return epicsAtomicCmpAndSwapPtrT ( & v, oldVal, newVal );
}
} /* end of namespace atomic */
} /* end of namespace epics */
#endif /* ifdef __cplusplus */
#endif /* epicsAtomic_h */

View File

@@ -0,0 +1,227 @@
/*************************************************************************\
* 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 epicsAtomicDefault_h
#define epicsAtomicDefault_h
#ifdef __cpluplus
extern "C" {
#endif
/*
* struct EpicsAtomicLockKey;
* epicsShareFunc void epicsAtomicReadMemoryBarrier ();
* epicsShareFunc void epicsAtomicWriteMemoryBarrier ();
* epicsShareFunc void epicsAtomicLock ( struct EpicsAtomicLockKey * );
* epicsShareFunc void epicsAtomicUnock ( struct EpicsAtomicLockKey * );
*/
/*
* incr
*/
#ifndef EPICS_ATOMIC_INCR_INTT
EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
{
EpicsAtomicLockKey key;
epicsAtomicLock ( & key );
const int result = ++(*pTarget);
epicsAtomicUnlock ( & key );
return result;
}
#endif
#ifndef EPICS_ATOMIC_INCR_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
{
EpicsAtomicLockKey key;
epicsAtomicLock ( & key );
const size_t result = ++(*pTarget);
epicsAtomicUnlock ( & key );
return result;
}
#endif
/*
* decr
*/
#ifndef EPICS_ATOMIC_DECR_INTT
EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
{
EpicsAtomicLockKey key;
epicsAtomicLock ( & key );
const int result = --(*pTarget);
epicsAtomicUnlock ( & key );
return result;
}
#endif
#ifndef EPICS_ATOMIC_DECR_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
{
EpicsAtomicLockKey key;
epicsAtomicLock ( & key );
const size_t result = --(*pTarget);
epicsAtomicUnlock ( & key );
return result;
}
#endif
/*
* add/sub
*/
#ifndef EPICS_ATOMIC_ADD_INTT
EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
{
EpicsAtomicLockKey key;
epicsAtomicLock ( & key );
const int result = *pTarget += delta;
epicsAtomicUnlock ( & key );
return result;
}
#endif
#ifndef EPICS_ATOMIC_ADD_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta )
{
EpicsAtomicLockKey key;
epicsAtomicLock ( & key );
const size_t result = *pTarget += delta;
epicsAtomicUnlock ( & key );
return result;
}
#endif
#ifndef EPICS_ATOMIC_SUB_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
{
EpicsAtomicLockKey key;
epicsAtomicLock ( & key );
const size_t result = *pTarget -= delta;
epicsAtomicUnlock ( & key );
return result;
}
#endif
/*
* set
*/
#ifndef EPICS_ATOMIC_SET_INTT
EPICS_ATOMIC_INLINE void epicsAtomicSetIntT ( int * pTarget, int newVal )
{
*pTarget = newVal;
epicsAtomicWriteMemoryBarrier ();
}
#endif
#ifndef EPICS_ATOMIC_SET_SIZET
EPICS_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
{
*pTarget = newVal;
epicsAtomicWriteMemoryBarrier ();
}
#endif
#ifndef EPICS_ATOMIC_SET_PTRT
EPICS_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget,
EpicsAtomicPtrT newVal )
{
*pTarget = newVal;
epicsAtomicWriteMemoryBarrier ();
}
#endif
/*
* get
*/
#ifndef EPICS_ATOMIC_GET_INTT
EPICS_ATOMIC_INLINE int epicsAtomicGetIntT ( const int * pTarget )
{
epicsAtomicReadMemoryBarrier ();
return *pTarget;
}
#endif
#ifndef EPICS_ATOMIC_GET_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
{
epicsAtomicReadMemoryBarrier ();
return *pTarget;
}
#endif
#ifndef EPICS_ATOMIC_GET_PTRT
EPICS_ATOMIC_INLINE EpicsAtomicPtrT
epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget )
{
epicsAtomicReadMemoryBarrier ();
return *pTarget;
}
#endif
/*
* cmp and swap
*/
#ifndef EPICS_ATOMIC_CAS_INTT
EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, int oldval, int newval )
{
EpicsAtomicLockKey key;
epicsAtomicLock ( & key );
const int cur = *pTarget;
if ( cur == oldval ) {
*pTarget = newval;
}
epicsAtomicUnlock ( & key );
return cur;
}
#endif
#ifndef EPICS_ATOMIC_CAS_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget,
size_t oldval, size_t newval )
{
EpicsAtomicLockKey key;
epicsAtomicLock ( & key );
const size_t cur = *pTarget;
if ( cur == oldval ) {
*pTarget = newval;
}
epicsAtomicUnlock ( & key );
return cur;
}
#endif
#ifndef EPICS_ATOMIC_CAS_PTRT
EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT (
EpicsAtomicPtrT * pTarget,
EpicsAtomicPtrT oldval, EpicsAtomicPtrT newval )
{
EpicsAtomicLockKey key;
epicsAtomicLock ( & key );
const EpicsAtomicPtrT cur = *pTarget;
if ( cur == oldval ) {
*pTarget = newval;
}
epicsAtomicUnlock ( & key );
return cur;
}
#endif
#ifdef __cpluplus
} /* end of extern "C" */
#endif
#endif /* epicsAtomicDefault_h */

View File

@@ -0,0 +1,222 @@
/*************************************************************************\
* 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 epicsAtomicMS_h
#define epicsAtomicMS_h
#include "epicsAssert.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifndef EPICS_ATOMIC_INCR_INTT
#define EPICS_ATOMIC_INCR_INTT
EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
{
STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) );
MS_LONG * const pTarg = ( MS_LONG * ) pTarget;
return MS_InterlockedIncrement ( pTarg );
}
#endif
#ifndef EPICS_ATOMIC_DECR_INTT
#define EPICS_ATOMIC_DECR_INTT
EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
{
STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) );
MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
return MS_InterlockedDecrement ( pTarg );
}
#endif
#ifndef EPICS_ATOMIC_ADD_INTT
#define EPICS_ATOMIC_ADD_INTT
EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
{
STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) );
MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
/* we dont use InterlockedAdd because only latest windows is supported */
return delta + ( int ) MS_InterlockedExchangeAdd ( pTarg,
( MS_LONG ) delta );
}
#endif
#ifndef EPICS_ATOMIC_CAS_INTT
#define EPICS_ATOMIC_CAS_INTT
EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget,
int oldVal, int newVal )
{
STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( int ) );
MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
return (int) MS_InterlockedCompareExchange ( pTarg,
(MS_LONG) newVal, (MS_LONG) oldVal );
}
#endif
#if ! defined ( MS_ATOMIC_64 )
/*
* necessary for next three functions
*
* looking at the MS documentation it appears that they will
* keep type long the same size as an int on 64 bit builds
*/
STATIC_ASSERT ( sizeof ( MS_LONG ) == sizeof ( size_t ) );
#ifndef EPICS_ATOMIC_INCR_SIZET
#define EPICS_ATOMIC_INCR_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
{
MS_LONG * const pTarg = ( MS_LONG * ) pTarget;
return MS_InterlockedIncrement ( pTarg );
}
#endif
#ifndef EPICS_ATOMIC_DECR_SIZET
#define EPICS_ATOMIC_DECR_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
{
MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
return MS_InterlockedDecrement ( pTarg );
}
#endif
#ifndef EPICS_ATOMIC_ADD_SIZET
#define EPICS_ATOMIC_ADD_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget,
size_t delta )
{
MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
/* we dont use InterlockedAdd because only latest windows is supported */
return delta + ( size_t ) MS_InterlockedExchangeAdd ( pTarg,
( MS_LONG ) delta );
}
#endif
#ifndef EPICS_ATOMIC_SUB_SIZET
#define EPICS_ATOMIC_SUB_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
{
MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
MS_LONG ldelta = (MS_LONG) delta;
/* we dont use InterlockedAdd because only latest windows is supported */
return ( ( size_t ) MS_InterlockedExchangeAdd ( pTarg, -ldelta ) ) - delta;
}
#endif
#ifndef EPICS_ATOMIC_CAS_SIZET
#define EPICS_ATOMIC_CAS_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT (
size_t * pTarget,
size_t oldVal, size_t newVal )
{
MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
return (size_t) MS_InterlockedCompareExchange ( pTarg,
(MS_LONG) newVal, (MS_LONG) oldVal );
}
#endif
#ifndef EPICS_ATOMIC_CAS_PTRT
#define EPICS_ATOMIC_CAS_PTRT
EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT (
EpicsAtomicPtrT * pTarget,
EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
{
MS_LONG * const pTarg = ( MS_LONG * ) ( pTarget );
return (EpicsAtomicPtrT) MS_InterlockedCompareExchange ( pTarg,
(MS_LONG) newVal, (MS_LONG) oldVal );
}
#endif
#else /* ! MS_ATOMIC_64 */
/*
* necessary for next three functions
*/
STATIC_ASSERT ( sizeof ( MS_LONGLONG ) == sizeof ( size_t ) );
#ifndef EPICS_ATOMIC_INCR_SIZET
#define EPICS_ATOMIC_INCR_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
{
MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) pTarget;
return ( size_t ) MS_InterlockedIncrement64 ( pTarg );
}
#endif
#ifndef EPICS_ATOMIC_DECR_SIZET
#define EPICS_ATOMIC_DECR_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
{
MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget );
return ( size_t ) MS_InterlockedDecrement64 ( pTarg );
}
#endif
#ifndef EPICS_ATOMIC_ADD_SIZET
#define EPICS_ATOMIC_ADD_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta )
{
MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget );
/* we dont use InterlockedAdd64 because only latest windows is supported */
return delta + ( size_t ) MS_InterlockedExchangeAdd64 ( pTarg,
( MS_LONGLONG ) delta );
}
#endif
#ifndef EPICS_ATOMIC_SUB_SIZET
#define EPICS_ATOMIC_SUB_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
{
MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget );
MS_LONGLONG ldelta = (MS_LONGLONG) delta;
/* we dont use InterlockedAdd64 because only latest windows is supported */
return (( size_t ) MS_InterlockedExchangeAdd64 ( pTarg, -ldelta )) - delta;
}
#endif
#ifndef EPICS_ATOMIC_CAS_SIZET
#define EPICS_ATOMIC_CAS_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget,
size_t oldVal, size_t newVal )
{
MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget );
return (size_t) MS_InterlockedCompareExchange64 ( pTarg,
(MS_LONGLONG) newVal,
(MS_LONGLONG) oldVal );
}
#endif
#ifndef EPICS_ATOMIC_CAS_PTRT
#define EPICS_ATOMIC_CAS_PTRT
EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT (
EpicsAtomicPtrT * pTarget,
EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
{
MS_LONGLONG * const pTarg = ( MS_LONGLONG * ) ( pTarget );
return (EpicsAtomicPtrT) MS_InterlockedCompareExchange64 ( pTarg,
(MS_LONGLONG) newVal, (MS_LONGLONG) oldVal );
}
#endif
#endif /* ! MS_ATOMIC_64 */
#ifdef __cplusplus
} /* end of extern "C" */
#endif /* __cplusplus */
#endif /* ifdef epicsAtomicMS_h */

View File

@@ -0,0 +1,22 @@
/*************************************************************************\
* 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"
// if the compiler is unable to inline then instantiate out-of-line
#ifndef EPICS_ATOMIC_INLINE
# define EPICS_ATOMIC_INLINE
# include "epicsAtomicOSD.h"
#endif

View File

@@ -0,0 +1,47 @@
/*************************************************************************\
* 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 epicsAtomicOSD_h
#define epicsAtomicOSD_h
#define VC_EXTRALEAN
#define STRICT
#include "windows.h"
#if defined ( _WIN64 )
# define MS_ATOMIC_64
#endif
#define MS_LONG LONG
#define MS_InterlockedExchange InterlockedExchange
#define MS_InterlockedCompareExchange InterlockedCompareExchange
#define MS_InterlockedIncrement InterlockedIncrement
#define MS_InterlockedDecrement InterlockedDecrement
#define MS_InterlockedExchange InterlockedExchange
#define MS_InterlockedExchangeAdd InterlockedExchangeAdd
#if defined ( MS_ATOMIC_64 )
# define MS_LONGLONG LONGLONG
# define MS_InterlockedIncrement64 InterlockedIncrement64
# define MS_InterlockedDecrement64 InterlockedDecrement64
# define MS_InterlockedExchange64 InterlockedExchange64
# define MS_InterlockedExchangeAdd64 InterlockedExchangeAdd64
# define MS_InterlockedCompareExchange InterlockedCompareExchange64
#endif
#include "epicsAtomicMS.h"
#include "epicsAtomicDefault.h"
#endif /* epicsAtomicOSD_h */

View File

@@ -0,0 +1,99 @@
/*************************************************************************\
* 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
*/
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#define epicsExportSharedSymbols
#include "epicsAssert.h"
#include "epicsAtomic.h"
// if the compiler is unable to inline then instantiate out-of-line
#ifndef EPICS_ATOMIC_INLINE
# define EPICS_ATOMIC_INLINE
# include "epicsAtomicOSD.h"
#endif
#ifndef EPICS_ATOMIC_LOCK
/*
* Slow, but probably correct on all systems.
* Useful only if something more efficent isnt
* provided based on knowledge of the compiler
* or OS
*
* A statically initialized pthread mutex doesnt
* need to be destroyed
*
* !!!!!
* !!!!! WARNING
* !!!!!
* !!!!! Do not use this implementation on systems where
* !!!!! code runs at interrupt context. If so, then
* !!!!! an implementation must be provided that is based
* !!!!! on a compiler intrinsic or an interrpt lock and or
* !!!!! a spin lock primitive
* !!!!!
*/
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void epicsAtomicLock ( EpicsAtomicLockKey * )
{
unsigned countDown = 1000u;
int status;
while ( true ) {
status = pthread_mutex_lock ( & mutex );
if ( status == 0 ) return;
assert ( status == EINTR );
static const useconds_t retryDelayUSec = 100000;
usleep ( retryDelayUSec );
countDown--;
assert ( countDown );
}
}
void epicsAtomicUnlock ( EpicsAtomicLockKey * )
{
const int status = pthread_mutex_unlock ( & mutex );
assert ( status == 0 );
}
#endif // ifndef EPICS_ATOMIC_LOCK
#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
// Slow, but probably correct on all systems.
// Useful only if something more efficent isnt
// provided based on knowledge of the compiler
// or OS
void epicsAtomicReadMemoryBarrier ()
{
EpicsAtomicLockKey key;
epicsAtomicLock ( & key );
epicsAtomicUnlock ( & key );
}
#endif
#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
// Slow, but probably correct on all systems.
// Useful only if something more efficent isnt
// provided based on knowledge of the compiler
// or OS
void epicsAtomicWriteMemoryBarrier ()
{
EpicsAtomicLockKey key;
epicsAtomicLock ( & key );
epicsAtomicUnlock ( & key );
}
#endif

View File

@@ -0,0 +1,35 @@
/*************************************************************************\
* 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 epicsAtomicOSD_h
#define epicsAtomicOSD_h
struct EpicsAtomicLockKey {};
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
epicsShareFunc void epicsAtomicLock ( struct EpicsAtomicLockKey * );
epicsShareFunc void epicsAtomicUnlock ( struct EpicsAtomicLockKey * );
#ifdef __cplusplus
} /* end of extern "C" */
#endif /* __cplusplus */
#include "epicsAtomicDefault.h"
#endif /* epicsAtomicOSD_h */

View File

@@ -0,0 +1,178 @@
/*************************************************************************\
* 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 epicsAtomicOSD_h
#define epicsAtomicOSD_h
#if defined ( __SunOS_5_10 )
/*
* atomic.h exists only in Solaris 10 or higher
*/
#include <atomic.h>
#include "epicsAssert.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
#define EPICS_ATOMIC_READ_MEMORY_BARRIER
EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier ()
{
membar_consumer ();
}
#endif
#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier ()
{
membar_producer ();
}
#endif
#ifndef EPICS_ATOMIC_CAS_INTT
#define EPICS_ATOMIC_CAS_INTT
EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget,
int oldVal, int newVal )
{
STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) );
unsigned * const pTarg = ( unsigned * ) pTarget;
return ( int ) atomic_cas_uint ( pTarg, ( unsigned ) oldVal,
( unsigned ) newVal );
}
#endif
#ifndef EPICS_ATOMIC_CAS_SIZET
#define EPICS_ATOMIC_CAS_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT (
size_t * pTarget,
size_t oldVal, size_t newVal )
{
STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) );
ulong_t * const pTarg = ( ulong_t * ) pTarget;
return ( size_t ) atomic_cas_ulong ( pTarg, oldVal, newVal );
}
#endif
#ifndef EPICS_ATOMIC_CAS_PTRT
#define EPICS_ATOMIC_CAS_PTRT
EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT (
EpicsAtomicPtrT * pTarget,
EpicsAtomicPtrT oldVal,
EpicsAtomicPtrT newVal )
{
return atomic_cas_ptr ( pTarget, oldVal, newVal );
}
#endif
#ifndef EPICS_ATOMIC_INCR_INTT
#define EPICS_ATOMIC_INCR_INTT
EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
{
STATIC_ASSERT ( sizeof ( unsigned ) == sizeof ( int ) );
unsigned * const pTarg = ( unsigned * ) ( pTarget );
return ( int ) atomic_inc_uint_nv ( pTarg );
}
#endif
#ifndef EPICS_ATOMIC_INCR_SIZET
#define EPICS_ATOMIC_INCR_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
{
STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) );
ulong_t * const pTarg = ( ulong_t * ) pTarget;
return ( size_t ) atomic_inc_ulong_nv ( pTarg );
}
#endif
#ifndef EPICS_ATOMIC_DECR_INTT
#define EPICS_ATOMIC_DECR_INTT
EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
{
STATIC_ASSERT ( sizeof ( unsigned ) == sizeof ( int ) );
unsigned * const pTarg = ( unsigned * ) ( pTarget );
return ( int ) atomic_dec_uint_nv ( pTarg );
}
#endif
#ifndef EPICS_ATOMIC_DECR_SIZET
#define EPICS_ATOMIC_DECR_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
{
STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) );
ulong_t * const pTarg = ( ulong_t * ) pTarget;
return ( size_t ) atomic_dec_ulong_nv ( pTarg );
}
#endif
#ifndef EPICS_ATOMIC_ADD_INTT
#define EPICS_ATOMIC_ADD_INTT
EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
{
STATIC_ASSERT ( sizeof ( unsigned ) == sizeof ( int ) );
unsigned * const pTarg = ( unsigned * ) ( pTarget );
return ( int ) atomic_add_int_nv ( pTarg, delta );
}
#endif
#ifndef EPICS_ATOMIC_ADD_SIZET
#define EPICS_ATOMIC_ADD_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget,
size_t delta )
{
STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) );
ulong_t * const pTarg = ( ulong_t * ) pTarget;
return ( size_t ) atomic_add_long_nv ( pTarg, ( long ) delta );
}
#endif
#ifndef EPICS_ATOMIC_SUB_SIZET
#define EPICS_ATOMIC_SUB_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget,
size_t delta )
{
STATIC_ASSERT ( sizeof ( ulong_t ) == sizeof ( size_t ) );
ulong_t * const pTarg = ( ulong_t * ) pTarget;
long sdelta = ( long ) delta;
return ( size_t ) atomic_add_long_nv ( pTarg, -sdelta );
}
#endif
#ifdef __cplusplus
} /* end of extern "C" */
#endif /* __cplusplus */
#endif /* ifdef __SunOS_5_10 */
struct EpicsAtomicLockKey {};
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
epicsShareFunc void epicsAtomicLock ( struct EpicsAtomicLockKey * );
epicsShareFunc void epicsAtomicUnlock ( struct EpicsAtomicLockKey * );
#ifdef __cplusplus
} /* end of extern "C" */
#endif /* __cplusplus */
#include "epicsAtomicDefault.h"
#endif /* epicsAtomicOSD_h */

View File

@@ -0,0 +1,21 @@
/*************************************************************************\
* 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"
// if the compiler is unable to inline then instantiate out-of-line
#ifndef EPICS_ATOMIC_INLINE
# define EPICS_ATOMIC_INLINE
# include "epicsAtomicOSD.h"
#endif

View File

@@ -0,0 +1,256 @@
/*************************************************************************\
* 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 epicsAtomicOSD_h
#define epicsAtomicOSD_h
/* This is needed for vxWorks 6.8 to prevent an obnoxious compiler warning */
#ifndef _VSB_CONFIG_FILE
# define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h>
#endif
#include "vxWorks.h" /* obtain the version of vxWorks */
#include "epicsAssert.h"
/*
* With vxWorks 6.6 and later we need to use vxAtomicLib
* to implement this functionality correctly on SMP systems
*/
#if _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606
#include <limits.h>
#include <vxAtomicLib.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
#define EPICS_ATOMIC_READ_MEMORY_BARRIER
EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier ()
{
VX_MEM_BARRIER_R ();
}
#endif
#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier ()
{
VX_MEM_BARRIER_W ();
}
#endif
/*
* we make the probably correct guess that if ULONG_MAX
* is the same as UINT_MAX then sizeof ( atomic_t )
* will be the same as sizeof ( size_t )
*
* if ULONG_MAX != UINT_MAX then its 64 bit vxWorks and
* WRS doesnt not supply at this time the atomic interface
* for 8 byte integers that is needed - so that architecture
* receives the lock synchronized version
*/
#if ULONG_MAX == UINT_MAX
STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( size_t ) );
STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( EpicsAtomicPtrT ) );
#ifndef EPICS_ATOMIC_INCR_SIZET
#define EPICS_ATOMIC_INCR_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
{
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
const atomic_t oldVal = vxAtomicInc ( pTarg );
return 1 + ( size_t ) ( oldVal );
}
#endif
#ifndef EPICS_ATOMIC_DECR_SIZET
#define EPICS_ATOMIC_DECR_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
{
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
const atomic_t oldVal = vxAtomicDec ( pTarg );
return ( ( size_t ) oldVal ) - 1u;
}
#endif
#ifndef EPICS_ATOMIC_ADD_SIZET
#define EPICS_ATOMIC_ADD_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta )
{
/*
* vxAtomicLib doc indicates that vxAtomicAdd is
* implemented using signed arithmetic, but it
* does not change the end result because twos
* complement addition is used in either case
*/
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
const atomic_t oldVal = vxAtomicAdd ( pTarg, (atomic_t) delta );
return delta + ( size_t ) oldVal;
}
#endif
#ifndef EPICS_ATOMIC_SUB_SIZET
#define EPICS_ATOMIC_SUB_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta )
{
/*
* vxAtomicLib doc indicates that vxAtomicSub is
* implemented using signed arithmetic, but it
* does not change the end result because twos
* complement subtraction is used in either case
*/
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
const atomic_t oldVal = vxAtomicSub ( pTarg, (atomic_t) delta );
return ( ( size_t ) oldVal ) - delta;
}
#endif
#ifndef EPICS_ATOMIC_CAS_SIZET
#define EPICS_ATOMIC_CAS_SIZET
EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget,
size_t oldVal, size_t newVal )
{
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
return ( size_t ) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal );
}
#endif
#ifndef EPICS_ATOMIC_CAS_PTRT
#define EPICS_ATOMIC_CAS_PTRT
EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget,
EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )
{
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
return (EpicsAtomicPtrT) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal );
}
#endif
#else /* ULONG_MAX == UINT_MAX */
/*
* if its 64 bit SMP vxWorks and the compiler doesnt
* have an intrinsic then maybe there isnt any way to
* implement these without using a global lock because
* size_t is maybe bigger than atomic_t
*
* I dont yet have access to vxWorks manuals for
* 64 bit systems so this is still undecided, but is
* defaulting now to a global lock
*/
#endif /* ULONG_MAX == UINT_MAX */
STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( int ) );
#ifndef EPICS_ATOMIC_INCR_INTT
#define EPICS_ATOMIC_INCR_INTT
EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget )
{
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
const atomic_t oldVal = vxAtomicInc ( pTarg );
return 1 + ( int ) oldVal;
}
#endif
#ifndef EPICS_ATOMIC_DECR_INTT
#define EPICS_ATOMIC_DECR_INTT
EPICS_ATOMIC_INLINE int epicsAtomicDecrIntT ( int * pTarget )
{
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
const atomic_t oldVal = vxAtomicDec ( pTarg );
return ( ( int ) oldVal ) - 1;
}
#endif
#ifndef EPICS_ATOMIC_ADD_INTT
#define EPICS_ATOMIC_ADD_INTT
EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta )
{
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
const atomic_t oldVal = vxAtomicAdd ( pTarg, (atomic_t) delta );
return delta + ( int ) oldVal;
}
#endif
#ifndef EPICS_ATOMIC_CAS_INTT
#define EPICS_ATOMIC_CAS_INTT
EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget,
int oldVal, int newVal )
{
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
return ( int ) vxCas ( pTarg, (atomic_t) oldVal, (atomic_t) newVal );
}
#endif
#ifdef __cplusplus
} /* end of extern "C" */
#endif /* __cplusplus */
#else /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */
#include "vxLib.h"
#include "intLib.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifndef EPICS_ATOMIC_LOCK
#define EPICS_ATOMIC_LOCK
typedef struct EpicsAtomicLockKey { int m_key; } EpicsAtomicLockKey;
EPICS_ATOMIC_INLINE void epicsAtomicLock ( EpicsAtomicLockKey * pKey )
{
pKey->m_key = intLock ();
}
EPICS_ATOMIC_INLINE void epicsAtomicUnlock ( EpicsAtomicLockKey * pKey )
{
intUnlock ( pKey->m_key );
}
#endif
#ifndef EPICS_ATOMIC_READ_MEMORY_BARRIER
#define EPICS_ATOMIC_READ_MEMORY_BARRIER
/*
* no need for memory barrior since prior to vxWorks 6.6 it is a single cpu system
* (we are not protecting against multiple access to memory mapped IO)
*/
EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier () {}
#endif
#ifndef EPICS_ATOMIC_WRITE_MEMORY_BARRIER
#define EPICS_ATOMIC_WRITE_MEMORY_BARRIER
/*
* no need for memory barrior since prior to vxWorks 6.6 it is a single cpu system
* (we are not protecting against multiple access to memory mapped IO)
*/
EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier () {}
#endif
#ifdef __cplusplus
} /* end of extern "C" */
#endif /* __cplusplus */
#endif /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */
#include "epicsAtomicDefault.h"
#endif /* epicsAtomicOSD_h */

View File

@@ -3,8 +3,7 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
@@ -14,12 +13,10 @@
#ifndef osdSockH
#define osdSockH
#ifdef __cplusplus
extern "C" {
#endif
/* This is needed for vxWorks 6.8 to prevent an obnoxious compiler warning */
#define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h>
#ifndef _VSB_CONFIG_FILE
# define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h>
#endif
#include <errno.h>
@@ -36,6 +33,11 @@ extern "C" {
#include <ioLib.h>
#include <hostLib.h>
#include <selectLib.h>
#ifdef __cplusplus
extern "C" {
#endif
/*This following is not defined in any vxWorks header files*/
int sysClkRateGet(void);

View File

@@ -109,6 +109,11 @@ epicsMutexTest_SRCS += epicsMutexTest.cpp
testHarness_SRCS += epicsMutexTest.cpp
TESTS += epicsMutexTest
TESTPROD_HOST += epicsAtomicTest
epicsAtomicTest_SRCS += epicsAtomicTest.cpp
testHarness_SRCS += epicsAtomicTest.cpp
TESTS += epicsAtomicTest
TESTPROD_HOST += epicsExceptionTest
epicsExceptionTest_SRCS += epicsExceptionTest.cpp
testHarness_SRCS += epicsExceptionTest.cpp
@@ -179,6 +184,10 @@ fdmgrTest_SRCS += fdmgrTest.c
fdmgrTest_LIBS += ca
# FIXME: program never exits.
TESTPROD_HOST += epicsAtomicPerform
epicsAtomicPerform_SRCS += epicsAtomicPerform.cpp
testHarness_SRCS += epicsAtomicPerform.cpp
TESTPROD_HOST += cvtFastPerform
cvtFastPerform_SRCS += cvtFastPerform.cpp
testHarness_SRCS += cvtFastPerform.cpp

View File

@@ -0,0 +1,506 @@
#include <cstdlib>
#include <cstdio>
#include <cassert>
#include <typeinfo>
#include "epicsInterrupt.h"
#include "epicsAtomic.h"
#include "epicsTime.h"
#include "epicsUnitTest.h"
#include "testMain.h"
using std :: size_t;
using namespace epics;
using namespace atomic;
class RefCtr {
public:
RefCtr ();
~RefCtr ();
void reference ();
void unreference ();
private:
size_t m_cnt;
};
class Ownership {
public:
Ownership ();
Ownership ( RefCtr & refCtr );
Ownership ( const Ownership & );
~Ownership ();
Ownership & operator = ( const Ownership & );
private:
RefCtr * _pRefCtr;
static RefCtr m_noOwnership;
};
inline RefCtr :: RefCtr ()
{
epicsAtomicSetSizeT ( & m_cnt, 0 );
}
inline RefCtr :: ~RefCtr ()
{
unsigned cnt = epicsAtomicGetSizeT ( & m_cnt );
assert ( cnt == 0u );
}
inline void RefCtr :: reference ()
{
epicsAtomicIncrSizeT ( & m_cnt );
}
inline void RefCtr :: unreference ()
{
epicsAtomicDecrSizeT ( & m_cnt );
}
RefCtr Ownership :: m_noOwnership;
inline Ownership :: Ownership () :
_pRefCtr ( & m_noOwnership )
{
m_noOwnership.reference ();
}
inline Ownership :: Ownership ( RefCtr & refCtr ) :
_pRefCtr ( & refCtr )
{
refCtr.reference ();
}
inline Ownership :: Ownership ( const Ownership & ownership ) :
_pRefCtr ( ownership._pRefCtr )
{
_pRefCtr->reference ();
}
inline Ownership :: ~Ownership ()
{
_pRefCtr->unreference ();
}
inline Ownership & Ownership ::
operator = ( const Ownership & ownership )
{
RefCtr * const pOldRefCtr = _pRefCtr;
_pRefCtr = ownership._pRefCtr;
_pRefCtr->reference ();
pOldRefCtr->unreference ();
return *this;
}
inline Ownership retOwnership ( const Ownership & ownership )
{
return Ownership ( ownership );
}
inline Ownership recurRetOwner10 ( const Ownership & ownershipIn )
{
Ownership ownership =
retOwnership (
retOwnership (
retOwnership (
retOwnership (
retOwnership ( ownershipIn ) ) ) ) );
return retOwnership (
retOwnership (
retOwnership (
retOwnership (
retOwnership ( ownership ) ) ) ) );
}
inline Ownership recurRetOwner100 ( const Ownership & ownershipIn )
{
Ownership ownership =
recurRetOwner10 (
recurRetOwner10 (
recurRetOwner10 (
recurRetOwner10 (
recurRetOwner10 ( ownershipIn ) ) ) ) );
return recurRetOwner10 (
recurRetOwner10 (
recurRetOwner10 (
recurRetOwner10 (
recurRetOwner10 ( ownership ) ) ) ) );
}
inline Ownership recurRetOwner1000 ( const Ownership & ownershipIn )
{
Ownership ownership =
recurRetOwner100 (
recurRetOwner100 (
recurRetOwner100 (
recurRetOwner100 (
recurRetOwner100 ( ownershipIn ) ) ) ) );
return recurRetOwner100 (
recurRetOwner100 (
recurRetOwner100 (
recurRetOwner100 (
recurRetOwner100 ( ownership ) ) ) ) );
}
inline void passRefOwnership ( const Ownership & ownershipIn, Ownership & ownershipOut )
{
ownershipOut = ownershipIn;
}
inline void passRefOwnership10 ( const Ownership & ownershipIn, Ownership & ownershipOut )
{
Ownership ownershipTmp0;
passRefOwnership ( ownershipIn, ownershipTmp0 );
Ownership ownershipTmp1;
passRefOwnership ( ownershipTmp0, ownershipTmp1 );
Ownership ownershipTmp2;
passRefOwnership ( ownershipTmp1, ownershipTmp2 );
Ownership ownershipTmp3;
passRefOwnership ( ownershipTmp2, ownershipTmp3 );
Ownership ownershipTmp4;
passRefOwnership ( ownershipTmp3, ownershipTmp4 );
Ownership ownershipTmp5;
passRefOwnership ( ownershipTmp4, ownershipTmp5 );
Ownership ownershipTmp6;
passRefOwnership ( ownershipTmp5, ownershipTmp6 );
Ownership ownershipTmp7;
passRefOwnership ( ownershipTmp6, ownershipTmp7 );
Ownership ownershipTmp8;
passRefOwnership ( ownershipTmp7, ownershipTmp8 );
passRefOwnership ( ownershipTmp8, ownershipOut );
}
inline void passRefOwnership100 ( const Ownership & ownershipIn, Ownership & ownershipOut )
{
Ownership ownershipTmp0;
passRefOwnership10 ( ownershipIn, ownershipTmp0 );
Ownership ownershipTmp1;
passRefOwnership10 ( ownershipTmp0, ownershipTmp1 );
Ownership ownershipTmp2;
passRefOwnership10 ( ownershipTmp1, ownershipTmp2 );
Ownership ownershipTmp3;
passRefOwnership10 ( ownershipTmp2, ownershipTmp3 );
Ownership ownershipTmp4;
passRefOwnership10 ( ownershipTmp3, ownershipTmp4 );
Ownership ownershipTmp5;
passRefOwnership10 ( ownershipTmp4, ownershipTmp5 );
Ownership ownershipTmp6;
passRefOwnership10 ( ownershipTmp5, ownershipTmp6 );
Ownership ownershipTmp7;
passRefOwnership10 ( ownershipTmp6, ownershipTmp7 );
Ownership ownershipTmp8;
passRefOwnership10 ( ownershipTmp7, ownershipTmp8 );
passRefOwnership10 ( ownershipTmp8, ownershipOut );
}
inline void passRefOwnership1000 ( const Ownership & ownershipIn, Ownership & ownershipOut )
{
Ownership ownershipTmp0;
passRefOwnership100 ( ownershipIn, ownershipTmp0 );
Ownership ownershipTmp1;
passRefOwnership100 ( ownershipTmp0, ownershipTmp1 );
Ownership ownershipTmp2;
passRefOwnership100 ( ownershipTmp1, ownershipTmp2 );
Ownership ownershipTmp3;
passRefOwnership100 ( ownershipTmp2, ownershipTmp3 );
Ownership ownershipTmp4;
passRefOwnership100 ( ownershipTmp3, ownershipTmp4 );
Ownership ownershipTmp5;
passRefOwnership100 ( ownershipTmp4, ownershipTmp5 );
Ownership ownershipTmp6;
passRefOwnership100 ( ownershipTmp5, ownershipTmp6 );
Ownership ownershipTmp7;
passRefOwnership100 ( ownershipTmp6, ownershipTmp7 );
Ownership ownershipTmp8;
passRefOwnership100 ( ownershipTmp7, ownershipTmp8 );
passRefOwnership100 ( ownershipTmp8, ownershipOut );
}
time_t extTime = 0;
template < class T >
class OrdinaryIncr {
public:
OrdinaryIncr () : m_target ( 0 ) {}
void run ();
void diagnostic ( double delay );
private:
T m_target;
};
// tests the time it takes to perform a call to an external
// function and also increment an integer word. The
// epicsInterruptIsInterruptContext function is an
// out-of-line function implemented in a sharable library
// so hopefully it wont be optimized away.
template < class T >
inline void OrdinaryIncr < T > :: run ()
{
m_target += epicsInterruptIsInterruptContext ();
m_target += epicsInterruptIsInterruptContext ();
m_target += epicsInterruptIsInterruptContext ();
m_target += epicsInterruptIsInterruptContext ();
m_target += epicsInterruptIsInterruptContext ();
m_target += epicsInterruptIsInterruptContext ();
m_target += epicsInterruptIsInterruptContext ();
m_target += epicsInterruptIsInterruptContext ();
m_target += epicsInterruptIsInterruptContext ();
m_target += epicsInterruptIsInterruptContext ();
}
template < class T >
void OrdinaryIncr < T > :: diagnostic ( double delay )
{
delay /= 10.0;
delay *= 1e6;
const char * const pName = typeid ( T ) . name ();
testDiag ( "raw incr of \"%s\" and a NOOP function call takes %f microseconds",
pName, delay );
}
template < class T >
class AtomicIncr {
public:
AtomicIncr () : m_target ( 0 ) {}
void run ();
void diagnostic ( double delay );
private:
T m_target;
};
template < class T >
inline void AtomicIncr < T > :: run ()
{
increment ( m_target );
increment ( m_target );
increment ( m_target );
increment ( m_target );
increment ( m_target );
increment ( m_target );
increment ( m_target );
increment ( m_target );
increment ( m_target );
increment ( m_target );
}
template < class T >
void AtomicIncr < T > :: diagnostic ( double delay )
{
delay /= 10.0;
delay *= 1e6;
const char * const pName = typeid ( T ) . name ();
testDiag ( "epicsAtomicIncr \"%s\" takes %f microseconds",
pName, delay );
}
template < class T > T trueValue ();
template < class T > T falseValue ();
// int
template <>
inline int trueValue < int > () { return 1; }
template <>
inline int falseValue < int > () { return 0; }
// size_t
template <>
inline size_t trueValue < size_t > () { return 1u; }
template <>
inline size_t falseValue < size_t > () { return 0u; }
// EpicsAtomicPtrT
template <>
inline EpicsAtomicPtrT trueValue < EpicsAtomicPtrT > ()
{ static char c; return & c; }
template <>
inline EpicsAtomicPtrT falseValue < EpicsAtomicPtrT > ()
{ return 0u; }
template < class T >
class AtomicCmpAndSwap {
public:
AtomicCmpAndSwap () : m_target ( 0 ) {}
void run ();
void diagnostic ( double delay );
private:
T m_target;
};
template < class T >
inline void AtomicCmpAndSwap < T > :: run ()
{
compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
compareAndSwap ( m_target, falseValue < T > (), trueValue < T > () );
}
template < class T >
void AtomicCmpAndSwap < T > :: diagnostic ( double delay )
{
delay /= 10.0;
delay *= 1e6;
const char * const pName = typeid ( T ) . name ();
testDiag ( "epicsAtomicCmpAndSwap of \"%s\" takes %f microseconds",
pName, delay );
}
template < class T >
class AtomicSet {
public:
AtomicSet () : m_target ( 0 ) {}
void run ();
void diagnostic ( double delay );
private:
T m_target;
};
template < class T >
inline void AtomicSet < T > :: run ()
{
set ( m_target, 0 );
set ( m_target, 0 );
set ( m_target, 0 );
set ( m_target, 0 );
set ( m_target, 0 );
set ( m_target, 0 );
set ( m_target, 0 );
set ( m_target, 0 );
set ( m_target, 0 );
set ( m_target, 0 );
}
template < class T >
void AtomicSet < T > :: diagnostic ( double delay )
{
delay /= 10.0;
delay *= 1e6;
const char * const pName = typeid ( T ) . name ();
testDiag ( "epicsAtomicSet of \"%s\" takes %f microseconds",
pName, delay );
}
static const unsigned N = 10000;
void recursiveOwnershipRetPerformance ()
{
RefCtr refCtr;
epicsTime begin = epicsTime::getCurrent ();
for ( size_t i = 0; i < N; i++ ) {
Ownership ownership ( refCtr );
recurRetOwner1000 ( ownership );
}
double delay = epicsTime::getCurrent () - begin;
delay /= N * 1000u; // convert to delay per call
delay *= 1e6; // convert to micro seconds
testDiag ( "retOwnership() takes %f microseconds", delay );
}
void ownershipPassRefPerformance ()
{
RefCtr refCtr;
epicsTime begin = epicsTime::getCurrent ();
for ( size_t i = 0; i < N; i++ ) {
Ownership ownershipSrc ( refCtr );
Ownership ownershipDest;
passRefOwnership1000 ( ownershipSrc, ownershipDest );
}
double delay = epicsTime::getCurrent () - begin;
delay /= N * 1000u; // convert to delay per call
delay *= 1e6; // convert to micro seconds
testDiag ( "passRefOwnership() takes %f microseconds", delay );
}
template < class T >
class Ten
{
public:
void run ();
void diagnostic ( double delay );
typedef Ten < Ten < T > > Hundred;
typedef Ten < Hundred > Thousand;
private:
T m_target;
};
template < class T >
inline void Ten < T > :: run ()
{
m_target.run ();
m_target.run ();
m_target.run ();
m_target.run ();
m_target.run ();
m_target.run ();
m_target.run ();
m_target.run ();
m_target.run ();
m_target.run ();
}
template < class T >
void Ten < T > :: diagnostic ( double delay )
{
m_target.diagnostic ( delay / 10.0 );
}
template < class T >
void measurePerformance ()
{
epicsTime begin = epicsTime::getCurrent ();
T target;
for ( size_t i = 0; i < N; i++ ) {
target.run ();
target.run ();
target.run ();
target.run ();
target.run ();
target.run ();
target.run ();
target.run ();
target.run ();
target.run ();
}
double delay = epicsTime::getCurrent () - begin;
delay /= ( N * 10u ); // convert to delay per call
target.diagnostic ( delay );
}
template < class T >
void measure ()
{
measurePerformance < typename Ten < T > :: Hundred > ();
}
MAIN ( epicsAtomicPerform )
{
testPlan ( 0 );
//
// The tests running here are measuring fast
// functions so they tend to be impacted
// by where the cache lines are wrt to the
// virtual pages perhap
//
measure < AtomicSet < int > > ();
measure < AtomicSet < size_t > > ();
measure < AtomicSet < void * > > ();
measure < OrdinaryIncr < int > > ();
measure < OrdinaryIncr < size_t > > ();
measure < AtomicIncr < int > > ();
measure < AtomicIncr < size_t > > ();
measure < AtomicCmpAndSwap < int > > ();
measure < AtomicCmpAndSwap < size_t > > ();
measure < AtomicCmpAndSwap < void * > > ();
recursiveOwnershipRetPerformance ();
ownershipPassRefPerformance ();
return testDone();
}

View File

@@ -0,0 +1,238 @@
#include <stdlib.h>
#include <assert.h>
#include "epicsAtomic.h"
#include "epicsTime.h"
#include "epicsThread.h"
#include "epicsUnitTest.h"
#include "testMain.h"
using namespace epics;
using namespace atomic;
template < class T >
struct TestDataIncrDecr {
T m_testValue;
size_t m_testIterations;
};
template < class T >
struct TestDataAddSub {
T m_testValue;
size_t m_testIterations;
static const T delta = 17;
};
template < class T >
static void incr ( void *arg )
{
TestDataIncrDecr < T > * const pTestData =
reinterpret_cast < TestDataIncrDecr < T > * > ( arg );
increment ( pTestData->m_testValue );
increment ( pTestData->m_testIterations );
}
template < class T >
static void decr ( void *arg )
{
TestDataIncrDecr < T > * const pTestData =
reinterpret_cast < TestDataIncrDecr < T > * > ( arg );
decrement ( pTestData->m_testValue );
increment ( pTestData->m_testIterations );
}
template < class T >
static void add ( void *arg )
{
TestDataAddSub < T > * const pTestData =
reinterpret_cast < TestDataAddSub < T > * > ( arg );
add ( pTestData->m_testValue, TestDataAddSub < T > :: delta );
increment ( pTestData->m_testIterations );
}
template < class T >
static void sub ( void *arg )
{
TestDataAddSub < T > * const pTestData =
reinterpret_cast < TestDataAddSub < T > * > ( arg );
subtract ( pTestData->m_testValue, TestDataAddSub < T > :: delta );
increment ( pTestData->m_testIterations );
}
template < class T >
struct TestDataCAS {
T m_testValue;
size_t m_testIterationsSet;
size_t m_testIterationsNotSet;
};
int isModulo ( size_t N, size_t n )
{
return ( n % N ) == 0u;
}
template < class T >
static T trueValue ();
template < class T >
static T falseValue ();
// int
template <>
inline int trueValue < int > () { return 1; }
template <>
inline int falseValue < int > () { return 0; }
// size_t
template <>
inline size_t trueValue < size_t > () { return 1u; }
template <>
inline size_t falseValue < size_t > () { return 0u; }
// EpicsAtomicPtrT
template <>
inline EpicsAtomicPtrT trueValue < EpicsAtomicPtrT > ()
{ static char c; return & c; }
template <>
inline EpicsAtomicPtrT falseValue < EpicsAtomicPtrT > ()
{ return 0u; }
template < class T >
static void cas ( void *arg )
{
TestDataCAS < T > * const pTestData =
reinterpret_cast < TestDataCAS < T > * > ( arg );
/*
* intentionally waste cpu and maximize
* contention for the shared data
*/
increment ( pTestData->m_testIterationsNotSet );
while ( ! compareAndSwap ( pTestData->m_testValue,
falseValue < T > (),
trueValue < T > () ) ) {
}
decrement ( pTestData->m_testIterationsNotSet );
set ( pTestData->m_testValue, falseValue < T > () );
increment ( pTestData->m_testIterationsSet );
}
template < class T >
void testIncrDecr ()
{
static const size_t N = 100;
static const T NT = static_cast < T > ( N );
const unsigned int stackSize =
epicsThreadGetStackSize ( epicsThreadStackSmall );
TestDataIncrDecr < T > testData = { 0, N };
set ( testData.m_testValue, NT );
testOk ( get ( testData.m_testValue ) == NT,
"set/get %u", testData.m_testValue );
set ( testData.m_testIterations, 0u );
testOk ( get ( testData.m_testIterations ) == 0u,
"set/get %u", testData.m_testIterations );
for ( size_t i = 0u; i < N; i++ ) {
epicsThreadCreate ( "incr",
50, stackSize, incr < T >, & testData );
epicsThreadCreate ( "decr",
50, stackSize, decr < T >, & testData );
}
while ( testData.m_testIterations < 2 * N ) {
epicsThreadSleep ( 0.01 );
}
testOk ( get ( testData.m_testIterations ) == 2 * N,
"incr/decr iterations %u",
testData.m_testIterations );
testOk ( get ( testData.m_testValue ) == NT,
"incr/decr final value %u",
testData.m_testValue );
}
template < class T >
void testAddSub ()
{
static const size_t N = 100;
static const T NDT = TestDataAddSub < T > :: delta *
static_cast < T > ( N );
const unsigned int stackSize =
epicsThreadGetStackSize ( epicsThreadStackSmall );
TestDataIncrDecr < T > testData = { 0, N };
set ( testData.m_testValue, NDT );
testOk ( get ( testData.m_testValue ) == NDT,
"set/get %u", testData.m_testValue );
set ( testData.m_testIterations, 0u );
testOk ( get ( testData.m_testIterations ) == 0u,
"set/get %u", testData.m_testIterations );
for ( size_t i = 0u; i < N; i++ ) {
epicsThreadCreate ( "add",
50, stackSize, add < T >, & testData );
epicsThreadCreate ( "sub",
50, stackSize, sub < T >, & testData );
}
while ( testData.m_testIterations < 2 * N ) {
epicsThreadSleep ( 0.01 );
}
testOk ( get ( testData.m_testIterations ) == 2 * N,
"add/sub iterations %u",
testData.m_testIterations );
testOk ( get ( testData.m_testValue ) == NDT,
"add/sub final value %u",
testData.m_testValue );
}
template < class T >
void testCAS ()
{
static const size_t N = 10;
const unsigned int stackSize =
epicsThreadGetStackSize ( epicsThreadStackSmall );
TestDataCAS < T > testData = { 0, N, N };
set ( testData.m_testIterationsSet, 0 );
testOk ( get ( testData.m_testIterationsSet ) == 0u,
"set/get %u", testData.m_testIterationsSet );
set ( testData.m_testIterationsNotSet, 0 );
testOk ( get ( testData.m_testIterationsNotSet ) == 0u,
"set/get %u", testData.m_testIterationsNotSet );
set ( testData.m_testValue, trueValue < T > () );
testOk ( get ( testData.m_testValue ) == trueValue < T > (),
"set/get a true value" );
for ( size_t i = 0u; i < N; i++ ) {
epicsThreadCreate ( "tns",
50, stackSize, cas < T >, & testData );
}
set ( testData.m_testValue, falseValue < T > () );
while ( testData.m_testIterationsSet < N ) {
epicsThreadSleep ( 0.01 );
}
testOk ( get ( testData.m_testIterationsSet ) == N,
"test and set iterations %u",
testData.m_testIterationsSet );
testOk ( get ( testData.m_testIterationsNotSet ) == 0u,
"test and set not-set tracking = %u",
testData.m_testIterationsNotSet );
}
MAIN ( epicsAtomicTest )
{
testPlan ( 31 );
testIncrDecr < int > ();
testIncrDecr < size_t > ();
testAddSub < int > ();
testAddSub < size_t > ();
testCAS < int > ();
testCAS < size_t > ();
testCAS < EpicsAtomicPtrT > ();
return testDone ();
}