o added epicsAtomic implementation including compiler and os specific files

o added functionality and performance testing
This commit is contained in:
Jeff Hill
2011-08-05 09:13:38 -06:00
committed by Andrew Johnson
parent fa55316272
commit 747a59fd7f
15 changed files with 1743 additions and 0 deletions
@@ -0,0 +1,27 @@
/*************************************************************************\
* 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 cdAtomic_h
#define cdAtomic_h
#if defined ( __cplusplus )
# define OSD_ATOMIC_INLINE inline
#else
# define OSD_ATOMIC_INLINE __inline__
#endif
#include "osdAtomic.h"
#endif /* cdAtomic_h */
@@ -0,0 +1,25 @@
/*************************************************************************\
* 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 cdAtomic_h
#define cdAtomic_h
#if __STDC_VERSION__ >= 199901L || defined ( __cplusplus )
# define OSD_ATOMIC_INLINE inline
#endif
#include "osdAtomic.h"
#endif /* cdAtomic_h */
@@ -0,0 +1,97 @@
/*************************************************************************\
* 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 cdAtomic_h
#define cdAtomic_h
#ifndef __GNUC__
# error this header is only for use with the gnu compiler
#endif
#define OSD_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_UINT_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__ )
#if GCC_ATOMIC_INTRINSICS_AVAIL_UINT_T \
&& defined GCC_ATOMIC_INTRINSICS_AVAIL_SIZE_T
#define OSD_ATOMIC_GCC
#ifdef __cplusplus
extern "C" {
#endif
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
{
return __sync_add_and_fetch ( pTarget, 1u );
}
OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
{
return __sync_sub_and_fetch ( pTarget, 1u );
}
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget,
size_t newValue )
{
*pTarget = newValue;
__sync_synchronize ();
}
OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget,
unsigned newValue )
{
*pTarget = newValue;
__sync_synchronize ();
}
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
{
__sync_synchronize ();
return *pTarget;
}
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
{
const size_t prev = __sync_lock_test_and_set ( pTarget, 1u );
return prev == 0;
}
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#else /* if GCC_ATOMIC_INTRINSICS_AVAIL */
/*
* not available as gcc intrinsics so we
* will employ an os specific inline solution
*/
# include "osdAtomic.h"
#endif /* if GCC_ATOMIC_INTRINSICS_AVAIL */
#endif /* cdAtomic_h */
@@ -0,0 +1,165 @@
/*************************************************************************\
* 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 cdAtomic_h
#define cdAtomic_h
#include "epicsAssert.h"
#ifndef _MSC_VER
# error this header file is only for use with with the Microsoft Compiler
#endif
#ifdef _MSC_EXTENSIONS
/*
* I have discovered an anomaly in visual c++ where
* the DLL instantiation of an exported inline interface
* does not occur in a c++ code unless "inline" is used.
*/
#if defined ( __cplusplus )
# define OSD_ATOMIC_INLINE inline
#elif defined ( _MSC_VER )
# define OSD_ATOMIC_INLINE __inline
#endif
#if defined ( _M_X64 ) || defined ( _M_IA64 )
# define OSD_ATOMIC_64
#endif /* defined ( _M_X64 ) || defined ( _M_IA64 ) */
#include <intrin.h>
#pragma intrinsic ( _InterlockedExchange )
#pragma intrinsic ( _InterlockedCompareExchange )
#pragma intrinsic ( _InterlockedIncrement )
#pragma intrinsic ( _InterlockedDecrement )
#pragma intrinsic ( _InterlockedExchange )
#pragma intrinsic ( _InterlockedExchangeAdd )
#if OSD_ATOMIC_64
# pragma intrinsic ( _InterlockedIncrement64 )
# pragma intrinsic ( _InterlockedDecrement64 )
# pragma intrinsic ( _InterlockedExchange64 )
# pragma intrinsic ( _InterlockedExchangeAdd64 )
#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 so 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
*/
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* necessary for next two functions */
STATIC_ASSERT ( sizeof ( long ) == sizeof ( unsigned ) );
OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal )
{
long * const pTarg = ( long * ) ( pTarget );
_InterlockedExchange ( pTarg, ( long ) newVal );
}
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
{
long * const pTarg = ( long * ) ( pTarget );
return _InterlockedCompareExchange ( pTarg, 1, 0 ) == 0;
}
#if ! OSD_ATOMIC_64
/*
* necessary for next four 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 ( long ) == sizeof ( size_t ) );
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
{
long * const pTarg = ( long * ) pTarget;
return _InterlockedIncrement ( pTarg );
}
OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
{
long * const pTarg = ( long * ) ( pTarget );
return _InterlockedDecrement ( pTarg );
}
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
{
long * const pTarg = ( long * ) ( pTarget );
_InterlockedExchange ( pTarg, ( long ) newVal );
}
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
{
long * const pTarg = ( long * ) ( pTarget );
return _InterlockedExchangeAdd ( pTarg, 0 );
}
#else /* ! OSD_ATOMIC_64 */
/*
* necessary for next four functions
*/
STATIC_ASSERT ( sizeof ( long long ) == sizeof ( size_t ) );
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
{
long long * const pTarg = ( long long * ) pTarget;
return _InterlockedIncrement64 ( pTarg );
}
OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
{
long long * const pTarg = ( long long * ) ( pTarget );
return _InterlockedDecrement64 ( pTarg );
}
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
{
long long * const pTarg = ( long long * ) ( pTarget );
_InterlockedExchange64 ( pTarg, ( long long ) newVal );
}
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
{
long long * const pTarg = ( long long * ) ( pTarget );
return _InterlockedExchangeAdd64 ( pTarg, 0 );
}
#endif /* ! OSD_ATOMIC_64 */
#ifdef __cplusplus
} /* end of extern "C" */
#endif /* __cplusplus */
#else /* ifdef _MSC_EXTENSIONS */
#if defined ( __cplusplus )
# define OSD_ATOMIC_INLINE inline
# include "osdAtomic.h"
#endif
#endif /* ifdef _MSC_EXTENSIONS */
#endif /* cdAtomic_h */
@@ -0,0 +1,27 @@
/*************************************************************************\
* 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 cdAtomic_h
#define cdAtomic_h
#if defined ( __cplusplus )
# define OSD_ATOMIC_INLINE inline
#else
# define OSD_ATOMIC_INLINE __inline
#endif
#include "osdAtomic.h"
#endif /* cdAtomic_h */
+99
View File
@@ -0,0 +1,99 @@
/*************************************************************************\
* 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
/*
* lock out other smp processors from accessing the target,
* sync target in cache, add one to target, flush target in
* cache, allow other smp processors to access the target,
* return new value of target as modified by this operation
*
* increment is chosen as the primitive here because,
* compared to add, it is more likely to be implemented
* atomically on old architectures such as 68k
*/
epicsShareFunc size_t epicsAtomicIncrSizeT ( size_t * pTarget );
/*
* lock out other smp processors from accessing the target,
* sync target in cache, subtract one from target, flush target
* in cache, allow out other smp processors to access the target,
* return new value of target as modified by this operation
*
* decrement is chosen as the primitive here because,
* compared to subtract, it is more likely to be implemented
* atomically on old architectures such as 68k
*/
epicsShareFunc size_t epicsAtomicDecrSizeT ( size_t * pTarget );
/*
* set target in cache, flush target in cache
*/
epicsShareFunc void epicsAtomicSetSizeT ( size_t * pTarget, size_t newValue );
epicsShareFunc void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newValue );
/*
* fetch target in cache, return new value of target
*/
epicsShareFunc size_t epicsAtomicGetSizeT ( const size_t * pTarget );
/*
* lock out other smp processors from accessing the target,
* sync target in cache, if target is zero set target to
* non-zero (true) value, flush target in cache, allow out
* other smp processors to access the target, return true if
* this request changed the target from a zero value to a
* non-zero (true) value and otherwise false
*
* test and set is chosen as the primitive here because,
* compared to comapare-and-swap it is more likely to
* be implemented atomically on old architectures such as 68k
*/
epicsShareFunc unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget );
/*
* the following are, never inline and always synchronized by a global
* mutual exclusion lock, implementations of the epicsAtomicXxxx interface
* which may used to implement the epicsAtomicXxxx functions when
* more efficent primitives aren't available
*/
epicsShareFunc size_t epicsLockedIncrSizeT ( size_t * pTarget );
epicsShareFunc size_t epicsLockedDecrSizeT ( size_t * pTarget );
epicsShareFunc void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal );
epicsShareFunc void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal );
epicsShareFunc size_t epicsLockedGetSizeT ( const size_t * pTarget );
epicsShareFunc unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget );
#ifdef __cplusplus
} /* end of extern "C" */
#endif
/*
* options for inline compiler instrinsic or os specific
* implementations of the above function prototypes
*/
#include "epicsAtomicCD.h"
#endif /* epicsAtomic_h */
+103
View File
@@ -0,0 +1,103 @@
/*************************************************************************\
* 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
*
* Provide a global mutex version of the atomic functions for when
* we dont have more efficent OS primitives or compiler intriniscs
* to use instead.
*
* We implement these mutex-based primitives upon the libCom private
* interface epicsMutexOsdXxxx because, in libCom, it is convenient
* to make this a standalone primitive upon which we can implement
* epicsMutex.
*/
#define epicsExportSharedSymbols
#include "epicsAtomic.h"
#include "epicsMutex.h"
namespace {
class AtomicGuard {
public:
AtomicGuard ();
~AtomicGuard ();
private:
static epicsMutexOSD & m_mutex;
};
//
// see c++ FAQ, static init order fiasco
//
epicsMutexOSD & AtomicGuard :: m_mutex = * epicsMutexOsdCreate ();
inline AtomicGuard :: AtomicGuard ()
{
const int status = epicsMutexOsdLock ( & m_mutex );
assert ( status == epicsMutexLockOK );
}
inline AtomicGuard :: ~AtomicGuard ()
{
epicsMutexOsdUnlock ( & m_mutex );
}
} // end of anonymous namespace
extern "C" {
size_t epicsLockedIncrSizeT ( size_t * pTarget )
{
AtomicGuard atomicGuard;
return ++(*pTarget);
}
size_t epicsLockedDecrSizeT ( size_t * pTarget )
{
AtomicGuard atomicGuard;
return --(*pTarget);
}
void epicsLockedSetSizeT ( size_t * pTarget, size_t newVal )
{
AtomicGuard atomicGuard;
*pTarget = newVal;
}
void epicsLockedSetUIntT ( unsigned * pTarget, unsigned newVal )
{
AtomicGuard atomicGuard;
*pTarget = newVal;
}
size_t epicsLockedGetSizeT ( const size_t * pTarget )
{
AtomicGuard atomicGuard;
return *pTarget;
}
unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget )
{
AtomicGuard atomicGuard;
const bool weWillSetIt = ( *pTarget == 0u );
if ( weWillSetIt ) {
*pTarget = 1u;
}
return weWillSetIt;
}
} // end of extern "C"
+72
View File
@@ -0,0 +1,72 @@
/*************************************************************************\
* 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 epicsAtomicLocked_h
#define epicsAtomicLocked_h
#if defined ( OSD_ATOMIC_INLINE )
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
{
return epicsLockedTestAndSetUIntT ( pTarget );
}
OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal )
{
epicsLockedSetUIntT ( pTarget, newVal );
}
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
{
return epicsLockedIncrSizeT ( pTarget );
}
OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
{
return epicsLockedDecrSizeT ( pTarget );
}
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
{
epicsLockedSetSizeT ( pTarget, newVal );
}
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
{
return epicsLockedGetSizeT ( pTarget );
}
#ifdef __cplusplus
} /* end of extern "C" */
#endif /* __cplusplus */
#else /* if defined ( OSD_ATOMIC_INLINE ) */
# define epicsAtomicIncrSizeT epicsLockedIncrSizeT
# define epicsAtomicDecrSizeT epicsLockedDecrSizeT
# define epicsAtomicSetSizeT epicsLockedSetSizeT
# define epicsAtomicSetUIntT epicsLockedSetUIntT
# define epicsAtomicGetSizeT epicsLockedGetSizeT
# define epicsAtomicTestAndSetUIntT epicsLockedTestAndSetUIntT
#endif /* if defined ( OSD_ATOMIC_INLINE ) */
#endif /* epicsAtomicLocked_h */
+45
View File
@@ -0,0 +1,45 @@
/*************************************************************************\
* 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
*/
#include "epicsAtomic.h"
/*
* OSD_ATOMIC_INLINE
* defined: define atomic functions in osdAtomic.h
* undefined: dont define atomic functions in osdAtomic.h
*
* OSD_ATOMIC_INLINE is typically set by the compiler specific file cdAtomic.h
*
* when we discover here that there is no implementation, and we guess that
* there isnt an inline keyword in the compiler then we define OSD_ATOMIC_INLINE
* empty and include osdAtomic.h to force an out of line implementation
*
* My first inclination was to place only one file of this type under os/default,
* but then this source file always includes default/osdAtomic.h, which isnt correct
* if a more specific os/xxx/osdAtromic.h exists, and so rather than duplicate an
* identical file in all of the os directories (that will get rediculous if there
* is ever a posix interface for the atomics) I moved it here to the osi directory.
* Another option would be to not make tthe current location be the first search
* in the gnu make VPATH, but I am somewhat nervous about changing something that
* fundamental in the build system.
*
* this behavior will work most of the time by defualt but it can always be
* replaced by an os specific implementation, which might be required if
* some of the functions are inline and some are not
*/
#ifndef OSD_ATOMIC_INLINE
# include "osdAtomic.h"
#endif
+130
View File
@@ -0,0 +1,130 @@
/*************************************************************************\
* 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 osdAtomic_h
#define osdAtomic_h
#if defined ( OSD_ATOMIC_INLINE )
#include <limits.h>
#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */
#include <stdint.h>
#include "epicsAssert.h"
#define STRICT
#define VC_EXTRALEAN
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* necessary for next two functions */
STATIC_ASSERT ( sizeof ( LONG ) == sizeof ( unsigned ) );
OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal )
{
LONG * const pTarg = ( LONG * ) ( pTarget );
InterlockedExchange ( pTarg, ( LONG ) newVal );
}
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
{
long * const pTarg = ( LONG * ) ( pTarget );
return InterlockedCompareExchange ( pTarg, 1, 0 ) == 0;
}
/*
* on win32 a LONG is 32 bits, but I am concerned that
* we shouldnt use LONG_MAX here because with certain
* compilers a long will be 64 bits wide
*/
#define WIN32_LONG_MAX 0xffffffff
#if SIZE_MAX == WIN32_LONG_MAX
/*
* necessary for next four 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 ( LONG ) == sizeof ( size_t ) );
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
{
LONG * const pTarg = ( LONG * ) pTarget;
return InterlockedIncrement ( pTarg );
}
OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
{
LONG * const pTarg = ( LONG * ) ( pTarget );
return InterlockedDecrement ( pTarg );
}
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
{
LONG * const pTarg = ( LONG * ) ( pTarget );
InterlockedExchange ( pTarg, ( LONG ) newVal );
}
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
{
LONG * const pTarg = ( LONG * ) ( pTarget );
return InterlockedExchangeAdd ( pTarg, 0 );
}
#else /* SIZE_MAX == WIN32_LONG_MAX */
/*
* necessary for next four functions
*/
STATIC_ASSERT ( sizeof ( LONGLONG ) == sizeof ( size_t ) );
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
{
LONGLONG * const pTarg = ( LONGLONG * ) pTarget;
return InterlockedIncrement64 ( pTarg );
}
OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
{
LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget );
return InterlockedDecrement64 ( pTarg );
}
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
{
LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget );
InterlockedExchange64 ( pTarg, ( LONGLONG ) newVal );
}
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
{
LONGLONG * const pTarg = ( LONGLONG * ) ( pTarget );
return InterlockedExchangeAdd64 ( pTarg, 0 );
}
#endif /* SIZE_MAX == WIN32_LONG_MAX */
#ifdef __cplusplus
} /* end of extern "C" */
#endif /* __cplusplus */
#endif /* if defined ( OSD_ATOMIC_INLINE ) */
#endif /* ifndef osdAtomic_h */
@@ -0,0 +1,21 @@
/*************************************************************************\
* 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 osdAtomic
#define osdAtomic
#include "epicsAtomicLocked.h"
#endif /* osdAtomic */
+105
View File
@@ -0,0 +1,105 @@
/*************************************************************************\
* 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 osdAtomic_h
#define osdAtomic_h
#if defined ( OSD_ATOMIC_INLINE )
/*
* atomic.h exists only in Solaris 10 or higher
*/
#if defined ( __SunOS_5_10 )
#include <limits.h>
#include <atomic.h>
#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
{
const uchar_t oldVal = atomic_cas_uint ( pTarget, 0u, 1u );
return oldVal == 0u;
}
OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal )
{
atomic_swap_uint ( pTarget, newVal );
}
#if SIZE_MAX == UINT_MAX
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
{
return atomic_inc_uint_nv ( pTarget );
}
OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
{
return atomic_dec_uint_nv ( pTarget );
}
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
{
atomic_swap_uint ( pTarget, newVal );
}
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
{
return atomic_or_uint_nv ( pTarget, 0U );
}
#else /* SIZE_MAX == UINT_MAX */
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
{
return atomic_inc_ulong_nv ( pTarget );
}
OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
{
return atomic_dec_ulong_nv ( pTarget );
}
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
{
atomic_swap_ulong ( pTarget, newval );
}
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
{
return atomic_or_ulong_nv ( pTarget, 0U );
}
#endif /* SIZE_MAX == UINT_MAX */
#ifdef __cplusplus
} /* end of extern "C" */
#endif /* __cplusplus */
#else /* ifdef __SunOS_5_10 */
#include "epicsAtomicLocked.h"
#endif /* ifdef __SunOS_5_10 */
#endif /* if defined ( OSD_ATOMIC_INLINE ) */
#endif /* osdAtomic_h */
+211
View File
@@ -0,0 +1,211 @@
/*************************************************************************\
* 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 osdAtomic_h
#define osdAtomic_h
#if defined ( OSD_ATOMIC_INLINE )
#include "vxWorks.h" /* obtain the version of vxWorks */
/*
* 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
#define __STDC_LIMIT_MACROS /* define SIZE_MAX for c++ */
#include <stdint.h>
#include <limits.h>
#include <vxAtomicLib.h>
#include "epicsAssert.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/*
* we make the probably correct guess that if SIZE_MAX
* is the same as UINT_MAX then sizeof ( atomic_t )
* will be the same as sizeof ( size_t )
*
* if SIZE_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 SIZE_MAX == UINT_MAX
STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( size_t ) );
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
{
/*
* vxAtomicLib doc indicates that vxAtomicInc is
* implemented using unsigned arithmetic
*/
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
const atomic_t oldVal = vxAtomicInc ( pTarg ) + 1;
return ( ( size_t ) ( oldVal ) ) + 1u;
}
OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
{
/*
* vxAtomicLib doc indicates that vxAtomicDec is
* implemented using unsigned arithmetic
*/
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
const atomic_t oldVal = vxAtomicDec ( pTarg ) - 1;
return ( ( size_t ) ( oldVal ) ) - 1u;
}
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
{
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
vxAtomicSet ( pTarg, newVal );
}
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
{
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
return ( size_t ) vxAtomicGet ( pTarg );
}
#else /* SIZE_MAX == UINT_MAX */
/*
* if its 64 bit 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 bigger than atomic_t
*/
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
{
return epicsLockedIncrSizeT ( pTarget );
}
OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
{
return epicsLockedDecrSizeT ( pTarget );
}
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
{
epicsLockedSetSizeT ( pTarget, newVal );
}
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
{
return epicsLockedGetSizeT ( pTarget );
}
#endif /* SIZE_MAX == UINT_MAX */
STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) );
OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal )
{
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
vxAtomicSet ( pTarg, newVal );
}
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
{
STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) );
atomic_t * const pTarg = ( atomic_t * ) ( pTarget );
return vxCas ( pTarget, 0, 1 ) != 0;
}
#ifdef __cplusplus
} /* end of extern "C" */
#endif /* __cplusplus */
#else /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */
#include "intLib.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget )
{
/*
* no need for memory barrior since this
* is a single cpu system.
*/
const int key = intLock ();
const size_t result = ++(*pTarget);
intUnlock ( key );
return result;
}
OSD_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget )
{
/*
* no need for memory barrior since this
* is a single cpu system
*/
const int key = intLock ();
const size_t result = --(*pTarget);
intUnlock ( key );
return result;
}
OSD_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newVal )
{
/*
* no need for memory barrior since this
* is a single cpu system
*/
*pTarget = newVal;
}
OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal )
{
/*
* no need for memory barrior since this
* is a single cpu system
*/
*pTarget = newVal;
}
OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget )
{
/*
* no need for memory barrior since this
* is a single cpu system
*/
return *pTarget;
}
OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget )
{
STATIC_ASSERT ( sizeof ( int ) == sizeof ( unsigned ) );
int * const pTarg = ( int * ) ( pTarget );
const BOOL weSetIt = vxTas ( pTarg, 0, 1 );
return weSetIt != 0;
}
#ifdef __cplusplus
} /* end of extern "C" */
#endif /* __cplusplus */
#endif /* _WRS_VXWORKS_MAJOR * 100 + _WRS_VXWORKS_MINOR >= 606 */
#endif /* if defined ( OSD_ATOMIC_INLINE ) */
#endif /* osdAtomic_h */
+499
View File
@@ -0,0 +1,499 @@
#include <cstdlib>
#include <cassert>
#include "epicsInterrupt.h"
#include "epicsAtomic.h"
#include "epicsTime.h"
#include "epicsUnitTest.h"
#include "testMain.h"
using std :: size_t;
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;
// 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.
inline void tenOrdinaryIncr ( size_t & target )
{
int result = 0;
result += epicsInterruptIsInterruptContext ();
result += epicsInterruptIsInterruptContext ();
result += epicsInterruptIsInterruptContext ();
result += epicsInterruptIsInterruptContext ();
result += epicsInterruptIsInterruptContext ();
result += epicsInterruptIsInterruptContext ();
result += epicsInterruptIsInterruptContext ();
result += epicsInterruptIsInterruptContext ();
result += epicsInterruptIsInterruptContext ();
result += epicsInterruptIsInterruptContext ();
target = static_cast < unsigned > ( result );
}
inline void oneHundredOrdinaryIncr ( size_t & target )
{
tenOrdinaryIncr ( target );
tenOrdinaryIncr ( target );
tenOrdinaryIncr ( target );
tenOrdinaryIncr ( target );
tenOrdinaryIncr ( target );
tenOrdinaryIncr ( target );
tenOrdinaryIncr ( target );
tenOrdinaryIncr ( target );
tenOrdinaryIncr ( target );
tenOrdinaryIncr ( target );
}
inline void oneThousandOrdinaryIncr ( size_t & target )
{
oneHundredOrdinaryIncr ( target );
oneHundredOrdinaryIncr ( target );
oneHundredOrdinaryIncr ( target );
oneHundredOrdinaryIncr ( target );
oneHundredOrdinaryIncr ( target );
oneHundredOrdinaryIncr ( target );
oneHundredOrdinaryIncr ( target );
oneHundredOrdinaryIncr ( target );
oneHundredOrdinaryIncr ( target );
oneHundredOrdinaryIncr ( target );
}
inline void tenAtomicIncr ( size_t & target )
{
epicsAtomicIncrSizeT ( & target );
epicsAtomicIncrSizeT ( & target );
epicsAtomicIncrSizeT ( & target );
epicsAtomicIncrSizeT ( & target );
epicsAtomicIncrSizeT ( & target );
epicsAtomicIncrSizeT ( & target );
epicsAtomicIncrSizeT ( & target );
epicsAtomicIncrSizeT ( & target );
epicsAtomicIncrSizeT ( & target );
epicsAtomicIncrSizeT ( & target );
}
inline void oneHundredAtomicIncr ( size_t & target )
{
tenAtomicIncr ( target );
tenAtomicIncr ( target );
tenAtomicIncr ( target );
tenAtomicIncr ( target );
tenAtomicIncr ( target );
tenAtomicIncr ( target );
tenAtomicIncr ( target );
tenAtomicIncr ( target );
tenAtomicIncr ( target );
tenAtomicIncr ( target );
}
inline void oneThousandAtomicIncr ( size_t & target )
{
oneHundredAtomicIncr ( target );
oneHundredAtomicIncr ( target );
oneHundredAtomicIncr ( target );
oneHundredAtomicIncr ( target );
oneHundredAtomicIncr ( target );
oneHundredAtomicIncr ( target );
oneHundredAtomicIncr ( target );
oneHundredAtomicIncr ( target );
oneHundredAtomicIncr ( target );
oneHundredAtomicIncr ( target );
}
inline void tenAtomicTestAndSet ( unsigned & target )
{
epicsAtomicTestAndSetUIntT ( & target );
epicsAtomicTestAndSetUIntT ( & target );
epicsAtomicTestAndSetUIntT ( & target );
epicsAtomicTestAndSetUIntT ( & target );
epicsAtomicTestAndSetUIntT ( & target );
epicsAtomicTestAndSetUIntT ( & target );
epicsAtomicTestAndSetUIntT ( & target );
epicsAtomicTestAndSetUIntT ( & target );
epicsAtomicTestAndSetUIntT ( & target );
epicsAtomicTestAndSetUIntT ( & target );
}
inline void oneHundredAtomicTestAndSet ( unsigned & target )
{
tenAtomicTestAndSet ( target );
tenAtomicTestAndSet ( target );
tenAtomicTestAndSet ( target );
tenAtomicTestAndSet ( target );
tenAtomicTestAndSet ( target );
tenAtomicTestAndSet ( target );
tenAtomicTestAndSet ( target );
tenAtomicTestAndSet ( target );
tenAtomicTestAndSet ( target );
tenAtomicTestAndSet ( target );
}
inline void oneThousandAtomicTestAndSet ( unsigned & target )
{
oneHundredAtomicTestAndSet ( target );
oneHundredAtomicTestAndSet ( target );
oneHundredAtomicTestAndSet ( target );
oneHundredAtomicTestAndSet ( target );
oneHundredAtomicTestAndSet ( target );
oneHundredAtomicTestAndSet ( target );
oneHundredAtomicTestAndSet ( target );
oneHundredAtomicTestAndSet ( target );
oneHundredAtomicTestAndSet ( target );
oneHundredAtomicTestAndSet ( target );
}
inline void tenAtomicSet ( size_t & target )
{
epicsAtomicSetSizeT ( & target, 0 );
epicsAtomicSetSizeT ( & target, 0 );
epicsAtomicSetSizeT ( & target, 0 );
epicsAtomicSetSizeT ( & target, 0 );
epicsAtomicSetSizeT ( & target, 0 );
epicsAtomicSetSizeT ( & target, 0 );
epicsAtomicSetSizeT ( & target, 0 );
epicsAtomicSetSizeT ( & target, 0 );
epicsAtomicSetSizeT ( & target, 0 );
epicsAtomicSetSizeT ( & target, 0 );
}
inline void oneHundredAtomicSet ( size_t & target )
{
tenAtomicSet ( target );
tenAtomicSet ( target );
tenAtomicSet ( target );
tenAtomicSet ( target );
tenAtomicSet ( target );
tenAtomicSet ( target );
tenAtomicSet ( target );
tenAtomicSet ( target );
tenAtomicSet ( target );
tenAtomicSet ( target );
}
inline void oneThousandAtomicSet ( size_t & target )
{
oneHundredAtomicSet ( target );
oneHundredAtomicSet ( target );
oneHundredAtomicSet ( target );
oneHundredAtomicSet ( target );
oneHundredAtomicSet ( target );
oneHundredAtomicSet ( target );
oneHundredAtomicSet ( target );
oneHundredAtomicSet ( target );
oneHundredAtomicSet ( target );
oneHundredAtomicSet ( target );
}
static const unsigned N = 10000;
void ordinaryIncrPerformance ()
{
epicsTime begin = epicsTime::getCurrent ();
size_t target;
epicsAtomicSetSizeT ( & target, 0 );
for ( unsigned i = 0; i < N; i++ ) {
oneThousandOrdinaryIncr ( target );
}
double delay = epicsTime::getCurrent () - begin;
testOk1 ( target == 0u );
delay /= N * 1000u; // convert to delay per call
delay *= 1e6; // convert to micro seconds
testDiag ( "raw incr and a NOOP function call takes %f microseconds", delay );
}
void epicsAtomicIncrPerformance ()
{
epicsTime begin = epicsTime::getCurrent ();
size_t target;
epicsAtomicSetSizeT ( & target, 0 );
for ( unsigned i = 0; i < N; i++ ) {
oneThousandAtomicIncr ( target );
}
double delay = epicsTime::getCurrent () - begin;
testOk1 ( target == N * 1000u );
delay /= N * 1000u; // convert to delay per call
delay *= 1e6; // convert to micro seconds
testDiag ( "epicsAtomicIncr() takes %f microseconds", delay );
}
void atomicCompareAndSetPerformance ()
{
epicsTime begin = epicsTime::getCurrent ();
size_t target;
epicsAtomicSetSizeT ( & target, 0 );
testOk1 ( ! target );
for ( unsigned i = 0; i < N; i++ ) {
oneThousandAtomicTestAndSet ( target );
}
double delay = epicsTime::getCurrent () - begin;
testOk1 ( target );
delay /= N * 1000u; // convert to delay per call
delay *= 1e6; // convert to micro seconds
testDiag ( "epicsAtomicCompareAndSet() takes %f microseconds", delay );
}
void recursiveOwnershipRetPerformance ()
{
RefCtr refCtr;
epicsTime begin = epicsTime::getCurrent ();
for ( unsigned 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 ( unsigned 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 );
}
void epicsAtomicSetPerformance ()
{
epicsTime begin = epicsTime::getCurrent ();
unsigned target;
for ( unsigned i = 0; i < N; i++ ) {
oneThousandAtomicSet ( target );
}
double delay = epicsTime::getCurrent () - begin;
testOk1 ( target == 0u );
delay /= N * 1000u; // convert to delay per call
delay *= 1e6; // convert to micro seconds
testDiag ( "epicsAtomicSet() takes %f microseconds", delay );
}
MAIN(osiAtomicTest)
{
testPlan(5);
//
// 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 perhaps
//
epicsAtomicSetPerformance ();
ordinaryIncrPerformance ();
epicsAtomicIncrPerformance ();
recursiveOwnershipRetPerformance ();
ownershipPassRefPerformance ();
atomicCompareAndSetPerformance ();
return testDone();
}
+117
View File
@@ -0,0 +1,117 @@
#include <stdlib.h>
#include <assert.h>
#include "epicsAtomic.h"
#include "epicsTime.h"
#include "epicsThread.h"
#include "epicsUnitTest.h"
#include "testMain.h"
typedef struct TestDataIncrDecr {
size_t m_testValue;
size_t m_testIterations;
} TestDataIncrDecr;
static void incr ( void *arg )
{
TestDataIncrDecr * const pTestData = (TestDataIncrDecr *) arg;
epicsAtomicIncrSizeT ( & pTestData->m_testValue );
epicsAtomicIncrSizeT ( & pTestData->m_testIterations );
}
static void decr ( void *arg )
{
TestDataIncrDecr * const pTestData = (TestDataIncrDecr *) arg;
epicsAtomicDecrSizeT ( & pTestData->m_testValue );
epicsAtomicIncrSizeT ( & pTestData->m_testIterations );
}
typedef struct TestDataTNS {
unsigned m_testValue;
size_t m_testIterationsSet;
size_t m_testIterationsNotSet;
} TestDataTNS;
int isModulo ( size_t N, size_t n )
{
return ( n % N ) == 0u;
}
static void tns ( void *arg )
{
TestDataTNS * const pTestData = (TestDataTNS *) arg;
/*
* intentionally waste cpu and maximize
* contention for the shared data
*/
epicsAtomicIncrSizeT ( & pTestData->m_testIterationsNotSet );
while ( ! epicsAtomicTestAndSetUIntT ( & pTestData->m_testValue ) ) {
}
epicsAtomicDecrSizeT ( & pTestData->m_testIterationsNotSet );
epicsAtomicSetUIntT ( & pTestData->m_testValue, 0u );
epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet );
}
MAIN(osiAtomicTest)
{
static const size_t N = 1000;
const unsigned int stackSize =
epicsThreadGetStackSize ( epicsThreadStackSmall );
testPlan(8);
{
size_t i;
TestDataIncrDecr testData = { 0, N };;
epicsAtomicSetSizeT ( & testData.m_testValue, N );
testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N,
"set/get %u", testData.m_testValue );
epicsAtomicSetSizeT ( & testData.m_testIterations, 0u );
testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 0u,
"set/get %u", testData.m_testIterations );
for ( i = 0u; i < N; i++ ) {
epicsThreadCreate ( "incr",
50, stackSize, incr, & testData );
epicsThreadCreate ( "decr",
50, stackSize, decr, & testData );
}
while ( testData.m_testIterations < 2 * N ) {
epicsThreadSleep ( 0.01 );
}
testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 2 * N,
"incr/decr iterations %u",
testData.m_testIterations );
testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N,
"incr/decr final value %u",
testData.m_testValue );
}
{
size_t i;
TestDataTNS testData = { 1, N, N };
epicsAtomicSetSizeT ( & testData.m_testIterationsSet, 0u );
testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == 0u,
"set/get %u", testData.m_testIterationsSet );
epicsAtomicSetSizeT ( & testData.m_testIterationsNotSet, 0u );
testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u,
"set/get %u", testData.m_testIterationsNotSet );
for ( i = 0u; i < N; i++ ) {
epicsThreadCreate ( "tns",
50, stackSize, tns, & testData );
}
epicsAtomicSetUIntT ( & testData.m_testValue, 0u );
while ( testData.m_testIterationsSet < N ) {
epicsThreadSleep ( 0.01 );
}
testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N,
"test and set iterations %u",
testData.m_testIterationsSet );
testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u,
"test and set not-set tracking = %u",
testData.m_testIterationsNotSet );
}
return testDone();
}