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:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
31
src/libCom/osi/compiler/clang/epicsAtomicCD.h
Normal file
31
src/libCom/osi/compiler/clang/epicsAtomicCD.h
Normal 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 */
|
||||
30
src/libCom/osi/compiler/default/epicsAtomicCD.h
Normal file
30
src/libCom/osi/compiler/default/epicsAtomicCD.h
Normal 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 */
|
||||
172
src/libCom/osi/compiler/gcc/epicsAtomicCD.h
Normal file
172
src/libCom/osi/compiler/gcc/epicsAtomicCD.h
Normal 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 */
|
||||
124
src/libCom/osi/compiler/msvc/epicsAtomicCD.h
Normal file
124
src/libCom/osi/compiler/msvc/epicsAtomicCD.h
Normal 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 */
|
||||
|
||||
31
src/libCom/osi/compiler/solStudio/epicsAtomicCD.h
Normal file
31
src/libCom/osi/compiler/solStudio/epicsAtomicCD.h
Normal 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 */
|
||||
236
src/libCom/osi/epicsAtomic.h
Normal file
236
src/libCom/osi/epicsAtomic.h
Normal 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 */
|
||||
227
src/libCom/osi/epicsAtomicDefault.h
Normal file
227
src/libCom/osi/epicsAtomicDefault.h
Normal 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 */
|
||||
|
||||
|
||||
222
src/libCom/osi/os/WIN32/epicsAtomicMS.h
Normal file
222
src/libCom/osi/os/WIN32/epicsAtomicMS.h
Normal 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 */
|
||||
|
||||
22
src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp
Normal file
22
src/libCom/osi/os/WIN32/epicsAtomicOSD.cpp
Normal 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
|
||||
|
||||
47
src/libCom/osi/os/WIN32/epicsAtomicOSD.h
Normal file
47
src/libCom/osi/os/WIN32/epicsAtomicOSD.h
Normal 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 */
|
||||
|
||||
99
src/libCom/osi/os/posix/epicsAtomicOSD.cpp
Normal file
99
src/libCom/osi/os/posix/epicsAtomicOSD.cpp
Normal 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
|
||||
|
||||
35
src/libCom/osi/os/posix/epicsAtomicOSD.h
Normal file
35
src/libCom/osi/os/posix/epicsAtomicOSD.h
Normal 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 */
|
||||
|
||||
178
src/libCom/osi/os/solaris/epicsAtomicOSD.h
Normal file
178
src/libCom/osi/os/solaris/epicsAtomicOSD.h
Normal 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 */
|
||||
|
||||
21
src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp
Normal file
21
src/libCom/osi/os/vxWorks/epicsAtomicOSD.cpp
Normal 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
|
||||
256
src/libCom/osi/os/vxWorks/epicsAtomicOSD.h
Normal file
256
src/libCom/osi/os/vxWorks/epicsAtomicOSD.h
Normal 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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
506
src/libCom/test/epicsAtomicPerform.cpp
Normal file
506
src/libCom/test/epicsAtomicPerform.cpp
Normal 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();
|
||||
}
|
||||
238
src/libCom/test/epicsAtomicTest.cpp
Normal file
238
src/libCom/test/epicsAtomicTest.cpp
Normal 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 ();
|
||||
}
|
||||
Reference in New Issue
Block a user