diff --git a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h index 29e0a728b..faf1c7886 100644 --- a/src/libCom/osi/compiler/gcc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/gcc/epicsAtomicCD.h @@ -83,6 +83,12 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) return *pTarget; } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + __sync_synchronize (); + return *pTarget; +} + OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { const size_t prev = __sync_lock_test_and_set ( pTarget, 1u ); diff --git a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h index 17a3bec9a..08cd5ea31 100644 --- a/src/libCom/osi/compiler/msvc/epicsAtomicCD.h +++ b/src/libCom/osi/compiler/msvc/epicsAtomicCD.h @@ -66,7 +66,7 @@ extern "C" { #endif /* __cplusplus */ -/* necessary for next two functions */ +/* necessary for next three functions */ STATIC_ASSERT ( sizeof ( long ) == sizeof ( unsigned ) ); OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) @@ -75,6 +75,12 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal _InterlockedExchange ( pTarg, ( long ) newVal ); } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + long * const pTarg = ( long * ) ( pTarget ); + return _InterlockedExchangeAdd ( pTarg, 0 ); +} + OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { long * const pTarg = ( long * ) ( pTarget ); diff --git a/src/libCom/osi/epicsAtomic.h b/src/libCom/osi/epicsAtomic.h index c94c2de1e..72bb63e54 100644 --- a/src/libCom/osi/epicsAtomic.h +++ b/src/libCom/osi/epicsAtomic.h @@ -58,6 +58,7 @@ epicsShareFunc void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newValue * fetch target in cache, return new value of target */ epicsShareFunc size_t epicsAtomicGetSizeT ( const size_t * pTarget ); +epicsShareFunc unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ); /* * lock out other smp processors from accessing the target, @@ -84,6 +85,7 @@ 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 epicsLockedGetUIntT ( const unsigned * pTarget ); epicsShareFunc unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget ); #ifdef __cplusplus diff --git a/src/libCom/osi/epicsAtomicLocked.cpp b/src/libCom/osi/epicsAtomicLocked.cpp index b9ea22757..625dea118 100644 --- a/src/libCom/osi/epicsAtomicLocked.cpp +++ b/src/libCom/osi/epicsAtomicLocked.cpp @@ -86,6 +86,12 @@ size_t epicsLockedGetSizeT ( const size_t * pTarget ) return *pTarget; } +unsigned epicsLockedGetUIntT ( const unsigned * pTarget ) +{ + AtomicGuard atomicGuard; + return *pTarget; +} + unsigned epicsLockedTestAndSetUIntT ( unsigned * pTarget ) { AtomicGuard atomicGuard; diff --git a/src/libCom/osi/epicsAtomicLocked.h b/src/libCom/osi/epicsAtomicLocked.h index 0aec9c8b5..1ca29fd4c 100644 --- a/src/libCom/osi/epicsAtomicLocked.h +++ b/src/libCom/osi/epicsAtomicLocked.h @@ -52,6 +52,11 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) return epicsLockedGetSizeT ( pTarget ); } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + return epicsLockedGetUIntT ( pTarget ); +} + #ifdef __cplusplus } /* end of extern "C" */ #endif /* __cplusplus */ @@ -63,6 +68,7 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) # define epicsAtomicSetSizeT epicsLockedSetSizeT # define epicsAtomicSetUIntT epicsLockedSetUIntT # define epicsAtomicGetSizeT epicsLockedGetSizeT +# define epicsAtomicGetUIntT epicsLockedGetUIntT # define epicsAtomicTestAndSetUIntT epicsLockedTestAndSetUIntT #endif /* if defined ( OSD_ATOMIC_INLINE ) */ diff --git a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h index 3c4ac85df..27b59b242 100644 --- a/src/libCom/osi/os/WIN32/epicsAtomicOSD.h +++ b/src/libCom/osi/os/WIN32/epicsAtomicOSD.h @@ -33,7 +33,7 @@ extern "C" { #endif /* __cplusplus */ -/* necessary for next two functions */ +/* necessary for next three functions */ STATIC_ASSERT ( sizeof ( LONG ) == sizeof ( unsigned ) ); OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal ) @@ -42,6 +42,12 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal InterlockedExchange ( pTarg, ( LONG ) newVal ); } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + LONG * const pTarg = ( LONG * ) ( pTarget ); + return InterlockedExchangeAdd ( pTarg, 0 ); +} + OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) { long * const pTarg = ( LONG * ) ( pTarget ); diff --git a/src/libCom/osi/os/solaris/epicsAtomicOSD.h b/src/libCom/osi/os/solaris/epicsAtomicOSD.h index 952531750..7a6946899 100644 --- a/src/libCom/osi/os/solaris/epicsAtomicOSD.h +++ b/src/libCom/osi/os/solaris/epicsAtomicOSD.h @@ -44,6 +44,16 @@ OSD_ATOMIC_INLINE void epicsAtomicSetUIntT ( unsigned * pTarget, unsigned newVal atomic_swap_uint ( pTarget, newVal ); } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + /* + * we cast away const, but are careful not to modify + * the target + */ + unsigned * const pTarg = ( unsigned * ) ( pTarget ); + return atomic_or_uint_nv ( pTarg, 0U ); +} + #if SIZE_MAX == UINT_MAX OSD_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ) diff --git a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h index 0230d1b24..76ecf0c84 100644 --- a/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h +++ b/src/libCom/osi/os/vxWorks/epicsAtomicOSD.h @@ -126,6 +126,13 @@ OSD_ATOMIC_INLINE unsigned epicsAtomicTestAndSetUIntT ( unsigned * pTarget ) return vxCas ( pTarg, 0, 1 ) != 0; } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * pTarget ) +{ + STATIC_ASSERT ( sizeof ( atomic_t ) == sizeof ( unsigned ) ); + atomic_t * const pTarg = ( atomic_t * ) ( pTarget ); + return ( unsigned ) vxAtomicGet ( pTarg ); +} + #ifdef __cplusplus } /* end of extern "C" */ #endif /* __cplusplus */ @@ -198,6 +205,15 @@ OSD_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ) return *pTarget; } +OSD_ATOMIC_INLINE unsigned epicsAtomicGetUIntT ( const unsigned * 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 ) ); diff --git a/src/libCom/test/epicsAtomicTest.c b/src/libCom/test/epicsAtomicTest.c index bf5d2cbd2..5e0760b44 100644 --- a/src/libCom/test/epicsAtomicTest.c +++ b/src/libCom/test/epicsAtomicTest.c @@ -48,6 +48,8 @@ static void tns ( void *arg ) epicsAtomicIncrSizeT ( & pTestData->m_testIterationsNotSet ); while ( ! epicsAtomicTestAndSetUIntT ( & pTestData->m_testValue ) ) { } + testOk ( epicsAtomicGetUIntT ( & pTestData->m_testValue ), + "test and set must leave operand in true state" ); epicsAtomicDecrSizeT ( & pTestData->m_testIterationsNotSet ); epicsAtomicSetUIntT ( & pTestData->m_testValue, 0u ); epicsAtomicIncrSizeT ( & pTestData->m_testIterationsSet ); @@ -58,59 +60,61 @@ MAIN(epicsAtomicTest) const unsigned int stackSize = epicsThreadGetStackSize ( epicsThreadStackSmall ); - testPlan(8); + static const size_t N_incrDecr = 100; + static const size_t N_testAndSet = 10; + + testPlan( 9 + N_testAndSet ); { - static const size_t N = 100; + size_t i; - TestDataIncrDecr testData = { 0, N };; - epicsAtomicSetSizeT ( & testData.m_testValue, N ); - testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N, + TestDataIncrDecr testData = { 0, N_incrDecr }; + epicsAtomicSetSizeT ( & testData.m_testValue, N_incrDecr ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N_incrDecr, "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 ); + for ( i = 0u; i < N_incrDecr; i++ ) { + epicsThreadCreate ( "incr", 50, stackSize, incr, & testData ); + epicsThreadCreate ( "decr", 50, stackSize, decr, & testData ); } - while ( testData.m_testIterations < 2 * N ) { + while ( testData.m_testIterations < 2 * N_incrDecr ) { 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 ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterations ) == 2 * N_incrDecr, + "incr/decr iterations %u", testData.m_testIterations ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testValue ) == N_incrDecr, + "incr/decr final value %u", testData.m_testValue ); } { - static const size_t N = 10; size_t i; - TestDataTNS testData = { 1, N, N }; + TestDataTNS testData = { 1, N_testAndSet, N_testAndSet }; 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++ ) { + for ( i = 0u; i < N_testAndSet; i++ ) { epicsThreadCreate ( "tns", 50, stackSize, tns, & testData ); } epicsAtomicSetUIntT ( & testData.m_testValue, 0u ); - while ( testData.m_testIterationsSet < N ) { + while ( testData.m_testIterationsSet < N_testAndSet ) { epicsThreadSleep ( 0.01 ); } - testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N, - "test and set iterations %u", - testData.m_testIterationsSet ); + testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsSet ) == N_testAndSet, + "test and set iterations %u", testData.m_testIterationsSet ); testOk ( epicsAtomicGetSizeT ( & testData.m_testIterationsNotSet ) == 0u, - "test and set not-set tracking = %u", - testData.m_testIterationsNotSet ); + "test and set not-set tracking = %u", testData.m_testIterationsNotSet ); + { + static unsigned setVal = 5; + epicsAtomicSetUIntT ( & testData.m_testValue, setVal ); + testOk ( epicsAtomicGetUIntT ( & testData.m_testValue ) == setVal, + "unsigned version of set and get must concur" ); + } } return testDone();