diff --git a/modules/libcom/src/osi/epicsAtomic.h b/modules/libcom/src/osi/epicsAtomic.h index ccb302f25..ed2422a3d 100644 --- a/modules/libcom/src/osi/epicsAtomic.h +++ b/modules/libcom/src/osi/epicsAtomic.h @@ -8,6 +8,25 @@ * in file LICENSE that is included with this distribution. \*************************************************************************/ +/** + * \file epicsAtomic.h + * + * \brief OS independent interface to perform atomic operations + * + * This is an operating system and compiler independent interface to an operating system and or compiler + * dependent implementation of several atomic primitives. + * + * These primitives can be safely used in a multithreaded programs on symmetric multiprocessing (SMP) + * systems. Where possible the primitives are implemented with compiler intrinsic wrappers for architecture + * specific instructions. Otherwise they are implemeted with OS specific functions and otherwise, when lacking + * a sufficently capable OS specific interface, then in some rare situations a mutual exclusion primitive is + * used for synchronization. + * + * In operating systems environments which allow C code to run at interrupt level the implementation must + * use interrupt level invokable CPU instruction primitives. + * + * All C++ functions are implemented in the namespace atomics which is nested inside of namespace epics. + */ /* * Author Jeffrey O. Hill * johill@lanl.gov @@ -26,67 +45,217 @@ extern "C" { #endif +/** Argument type for atomic operations on pointers*/ typedef void * EpicsAtomicPtrT; -/* load target into cache */ +/** \brief load target into cache + * + * load target into cache + **/ EPICS_ATOMIC_INLINE void epicsAtomicReadMemoryBarrier (void); -/* push cache version of target into target */ +/** \brief push cache version of target into target + * + * push cache version of target into target + */ EPICS_ATOMIC_INLINE void epicsAtomicWriteMemoryBarrier (void); -/* - * lock out other smp processors from accessing the target, +/** \brief atomic increment on size_t value + * + * 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 + * + * \param pTarget pointer to target + * + * \return New value of target */ EPICS_ATOMIC_INLINE size_t epicsAtomicIncrSizeT ( size_t * pTarget ); + + /** \brief atomic increment on int value + * + * 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 + * + * \param pTarget pointer to target + * + * \return New value of target + */ EPICS_ATOMIC_INLINE int epicsAtomicIncrIntT ( int * pTarget ); -/* - * lock out other smp processors from accessing the target, +/** \brief atomic decrement on size_t value + * + * 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 + * + * \param pTarget pointer to target + * + * \return New value of target */ EPICS_ATOMIC_INLINE size_t epicsAtomicDecrSizeT ( size_t * pTarget ); + +/** \brief atomic decrement on int value + * + * 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 + * + * \param pTarget pointer to target + * + * \return New value of target + */ EPICS_ATOMIC_INLINE 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 + /** \brief atomic addition on size_t value + * + * Lock out other smp processors from accessing the target, + * load target into cache, add \p delta to target, flush cache + * to target, allow other smp processors to access the target, + * return new value of target as modified by this operation + * + * \param pTarget pointer to target + * \param delta value to add to target + * + * \return New value of target + */ +EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta ); + +/** \brief atomic subtraction on size_t value + * + * Lock out other smp processors from accessing the target, + * load target into cache, subtract \p delta from target, flush cache * to target, allow other smp processors to access the target, * return new value of target as modified by this operation + * + * \param pTarget pointer to target + * \param delta value to subtract from target + * + * \return New value of target */ -EPICS_ATOMIC_INLINE size_t epicsAtomicAddSizeT ( size_t * pTarget, size_t delta ); EPICS_ATOMIC_INLINE size_t epicsAtomicSubSizeT ( size_t * pTarget, size_t delta ); + +/** \brief atomic addition on int value + * + * Lock out other smp processors from accessing the target, + * load target into cache, add \p delta to target, flush cache + * to target, allow other smp processors to access the target, + * return new value of target as modified by this operation + * + * \param pTarget pointer to target + * \param delta value to add to target + * + * \return New value of target + */ EPICS_ATOMIC_INLINE int epicsAtomicAddIntT ( int * pTarget, int delta ); -/* - * set cache version of target, flush cache to target - */ + /** \brief atomically assign size_t value to variable + * + * set cache version of target to new value, flush cache to target + * + * \param pTarget pointer to target + * \param newValue desired value of target + */ EPICS_ATOMIC_INLINE void epicsAtomicSetSizeT ( size_t * pTarget, size_t newValue ); + + /** \brief atomically assign int value to variable + * + * set cache version of target to new value, flush cache to target + * + * \param pTarget pointer to target + * \param newValue desired value of target + */ EPICS_ATOMIC_INLINE void epicsAtomicSetIntT ( int * pTarget, int newValue ); + + /** \brief atomically assign pointer value to variable + * + * set cache version of target to new value, flush cache to target + * + * \param pTarget pointer to target + * \param newValue desired value of target + */ EPICS_ATOMIC_INLINE void epicsAtomicSetPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT newValue ); -/* +/** \brief atomically load and return size_t value + * * fetch target into cache, return new value of target + * + * \param pTarget pointer to target + * + * \return value of target */ EPICS_ATOMIC_INLINE size_t epicsAtomicGetSizeT ( const size_t * pTarget ); + +/** \brief atomically load and return int value + * + * fetch target into cache, return new value of target + * + * \param pTarget pointer to target + * + * \return value of target + */ EPICS_ATOMIC_INLINE int epicsAtomicGetIntT ( const int * pTarget ); + +/** \brief atomically load and return pointer value + * + * fetch target into cache, return new value of target + * + * \param pTarget pointer to target + * + * \return value of target + */ EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicGetPtrT ( const EpicsAtomicPtrT * pTarget ); -/* +/** \brief atomically compare size_t value with expected and if equal swap with new value + * * 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 + * load target into cache. If target is equal to \p oldVal, set target + * to \p newVal, flush cache to target, allow other smp processors + * to access the target + * + * \param pTarget pointer to target + * \param oldVal value that will be compared with target + * \param newVal value that will be set to target if oldVal == target + * + * \return the original value stored in the target */ EPICS_ATOMIC_INLINE size_t epicsAtomicCmpAndSwapSizeT ( size_t * pTarget, size_t oldVal, size_t newVal ); + +/** \brief atomically compare int value with expected and if equal swap with new value + * + * lock out other smp processors from accessing the target, + * load target into cache. If target is equal to \p oldVal, set target + * to \p newVal, flush cache to target, allow other smp processors + * to access the target + * + * \param pTarget pointer to target + * \param oldVal value that will be compared with target + * \param newVal value that will be set to target if oldVal == target + * + * \return the original value stored in the target + */ EPICS_ATOMIC_INLINE int epicsAtomicCmpAndSwapIntT ( int * pTarget, int oldVal, int newVal ); + +/** \brief atomically compare int value with expected and if equal swap with new value + * + * lock out other smp processors from accessing the target, + * load target into cache. If target is equal to \p oldVal, set target + * to \p newVal, flush cache to target, allow other smp processors + * to access the target + * + * \param pTarget pointer to target + * \param oldVal value that will be compared with target + * \param newVal value that will be set to target if oldVal == target + * + * \return the original value stored in the target + */ EPICS_ATOMIC_INLINE EpicsAtomicPtrT epicsAtomicCmpAndSwapPtrT ( EpicsAtomicPtrT * pTarget, EpicsAtomicPtrT oldVal, @@ -115,94 +284,233 @@ namespace atomic { * overloaded c++ interface */ -/************* incr ***************/ +/** \brief C++ API for atomic size_t increment + * + * C++ API for atomic size_t increment. + * + * \param v variable to increment + * + * \return new value + */ EPICS_ATOMIC_INLINE size_t increment ( size_t & v ) { return epicsAtomicIncrSizeT ( & v ); } +/** \brief C++ API for atomic int increment + * + * C++ API for atomic int increment. + * + * \param v variable to increment + * + * \return new value + */ EPICS_ATOMIC_INLINE int increment ( int & v ) { return epicsAtomicIncrIntT ( & v ); } -/************* decr ***************/ +/** \brief C++ API for atomic size_t decrement + * + * C++ API for atomic size_t decrement + * + * \param v variable to decrement + * + * \return new value + */ EPICS_ATOMIC_INLINE size_t decrement ( size_t & v ) { return epicsAtomicDecrSizeT ( & v ); } +/** \brief C++ API for atomic int decrement + * + * C++ API for atomic int decrement + * + * \param v variable to decrement + * + * \return new value + */ EPICS_ATOMIC_INLINE int decrement ( int & v ) { return epicsAtomicDecrIntT ( & v ); } -/************* add ***************/ +/** \brief C++ API for atomic size_t addition + * + * C++ API for atomic size_t addition + * + * \param v variable to add to + * \param delta value to add to \p v + * + * \return new value + */ EPICS_ATOMIC_INLINE size_t add ( size_t & v, size_t delta ) { return epicsAtomicAddSizeT ( & v, delta ); } +/** \brief C++ API for atomic int addition + * + * C++ API for atomic int addition + * + * \param v variable to add to + * \param delta value to add to \p v + * + * \return new value + */ EPICS_ATOMIC_INLINE int add ( int & v, int delta ) { return epicsAtomicAddIntT ( & v, delta ); } -/************* sub ***************/ +/** \brief C++ API for atomic size_t subtraction + * + * C++ API for atomic size_t subtraction + * + * \param v variable to subtract from + * \param delta value to subtract from \p v + * + * \return new value + */ EPICS_ATOMIC_INLINE size_t subtract ( size_t & v, size_t delta ) { return epicsAtomicSubSizeT ( & v, delta ); } +/** \brief C++ API for atomic int subtraction + * + * C++ API for atomic int subtraction + * + * \param v variable to subtract from + * \param delta value to subtract from \p v + * + * \return new value + */ EPICS_ATOMIC_INLINE int subtract ( int & v, int delta ) { return epicsAtomicAddIntT ( & v, -delta ); } -/************* set ***************/ +/** \brief C++ API for atomic size_t assignment + * + * C++ API for atomic size_t assignment + * + * \param v variable to assign to + * \param newValue new value for \p v + */ EPICS_ATOMIC_INLINE void set ( size_t & v , size_t newValue ) { epicsAtomicSetSizeT ( & v, newValue ); } +/** \brief C++ API for atomic int assignment + * + * C++ API for atomic int assignment + * + * \param v variable to assign to + * \param newValue new value for \p v + */ EPICS_ATOMIC_INLINE void set ( int & v, int newValue ) { epicsAtomicSetIntT ( & v, newValue ); } +/** \brief C++ API for atomic pointer assignment + * + * C++ API for atomic pointer assignment + * + * \param v variable to assign to + * \param newValue new value for \p v + */ EPICS_ATOMIC_INLINE void set ( EpicsAtomicPtrT & v, EpicsAtomicPtrT newValue ) { epicsAtomicSetPtrT ( & v, newValue ); } -/************* get ***************/ +/** \brief C++ API for atomic size_t load value + * + * C++ API for atomic size_t load value + * + * \param v variable to load + * + * \return value of \p v + */ EPICS_ATOMIC_INLINE size_t get ( const size_t & v ) { return epicsAtomicGetSizeT ( & v ); } +/** \brief C++ API for atomic int load value + * + * C++ API for atomic int load value + * + * \param v variable to load + * + * \return value of \p v + */ EPICS_ATOMIC_INLINE int get ( const int & v ) { return epicsAtomicGetIntT ( & v ); } +/** \brief C++ API for atomic pointer load value + * + * C++ API for atomic pointer load value + * + * \param v variable to load + * + * \return value of \p v + */ EPICS_ATOMIC_INLINE EpicsAtomicPtrT get ( const EpicsAtomicPtrT & v ) { return epicsAtomicGetPtrT ( & v ); } -/************* cas ***************/ +/** \brief C++ API for atomic size_t compare-and-swap + * + * C++ API for atomic size_t compare-and-swap. Atomic operation that compares \p v with \p oldVal + * and if \p v == \v oldVal, sets \p v to \v newVal + * + * \param v variable to compare and swap + * \param oldVal value to compare to \p \v + * \param newVal value to set to \p v + * + * \return original value stored in \p v + */ EPICS_ATOMIC_INLINE size_t compareAndSwap ( size_t & v, size_t oldVal, size_t newVal ) { return epicsAtomicCmpAndSwapSizeT ( & v, oldVal, newVal ); } +/** \brief C++ API for atomic int compare-and-swap + * + * C++ API for atomic size_t compare-and-swap. Atomic operation that compares \p v with \p oldVal + * and if \p v == \v oldVal, sets \p v to \v newVal + * + * \param v variable to compare and swap + * \param oldVal value to compare to \p \v + * \param newVal value to set to \p v + * + * \return original value stored in \p v + */ EPICS_ATOMIC_INLINE int compareAndSwap ( int & v, int oldVal, int newVal ) { return epicsAtomicCmpAndSwapIntT ( & v, oldVal, newVal ); } +/** \brief C++ API for atomic pointer compare-and-swap + * + * C++ API for atomic size_t compare-and-swap. Atomic operation that compares \p v with \p oldVal + * and if \p v == \v oldVal, sets \p v to \v newVal + * + * \param v variable to compare and swap + * \param oldVal value to compare to \p \v + * \param newVal value to set to \p v + * + * \return original value stored in \p v + */ EPICS_ATOMIC_INLINE EpicsAtomicPtrT compareAndSwap ( EpicsAtomicPtrT & v, EpicsAtomicPtrT oldVal, EpicsAtomicPtrT newVal )