📄 atomicbase.h
字号:
#include <c_asm.h>
/* Increment by 1 and return new value */
inline INT32
HXAtomicIncRetINT32(INT32* pNum)
{
return asm (
"10: ldl_l %t0, (%a0);" // Load-lock value into a register
" addl %t0, 1, %t0;" // Increment value
" or %t0, %zero, %v0;" // set new value for return.
" stl_c %t0, (%a0);" // Save new value into *pNum
" beq %t0, 10b;" // Retry if sequence failed
, pNum);
}
/* Decrement by 1 and return new value */
inline INT32
HXAtomicDecRetINT32(INT32* pNum)
{
return asm (
"10: ldl_l %t0, (%a0);" // Load-lock value into a register
" subl %t0, 1, %t0;" // Decrement value
" or %t0, %zero, %v0;" // set new value for return.
" stl_c %t0, (%a0);" // Save new value into *pNum
" beq %t0, 10b;" // Retry if sequence failed
, pNum);
}
/* Add n and return new value */
inline INT32
HXAtomicAddRetINT32(INT32* pNum, INT32 n)
{
return asm (
"10: ldl_l %t0, (%a0);" // Load-lock value into a register
" addl %t0, %a1, %t0;" // Add n to value
" or %t0, %zero, %v0;" // set new value for return.
" stl_c %t0, (%a0);" // Save new value into *pNum
" beq %t0, 10b;" // Retry if sequence failed
, pNum, n);
}
/* Subtract n and return new value */
inline INT32
HXAtomicSubRetINT32(INT32* pNum, INT32 n)
{
return asm (
"10: ldl_l %t0, (%a0);" // Load-lock value into a register
" subl %t0, %a1, %t0;" // Subtract n from value
" or %t0, %zero, %v0;" // set new value for return.
" stl_c %t0, (%a0);" // Save new value into *pNum
" beq %t0, 10b;" // Retry if sequence failed
, pNum, n);
}
/* Increment by 1 and return new value */
inline UINT32
HXAtomicIncRetUINT32(UINT32* pNum)
{
return asm (
"10: ldl_l %t0, (%a0);" // Load-lock value into a register
" addl %t0, 1, %t0;" // Increment value
" or %t0, %zero, %v0;" // set new value for return.
" stl_c %t0, (%a0);" // Save new value into *pNum
" beq %t0, 10b;" // Retry if sequence failed
, pNum);
}
/* Decrement by 1 and return new value */
inline UINT32
HXAtomicDecRetUINT32(UINT32* pNum)
{
return asm (
"10: ldl_l %t0, (%a0);" // Load-lock value into a register
" subl %t0, 1, %t0;" // Decrement value
" or %t0, %zero, %v0;" // set new value for return.
" stl_c %t0, (%a0);" // Save new value into *pNum
" beq %t0, 10b;" // Retry if sequence failed
, pNum);
}
/* Add n and return new value */
inline UINT32
HXAtomicAddRetUINT32(UINT32* pNum, UINT32 n)
{
return asm (
"10: ldl_l %t0, (%a0);" // Load-lock value into a register
" addl %t0, %a1, %t0;" // Add n to value
" or %t0, %zero, %v0;" // set new value for return.
" stl_c %t0, (%a0);" // Save new value into *pNum
" beq %t0, 10b;" // Retry if sequence failed
, pNum, n);
}
/* Subtract n and return new value */
inline UINT32
HXAtomicSubRetUINT32(UINT32* pNum, UINT32 n)
{
return asm (
"10: ldl_l %t0, (%a0);" // Load-lock value into a register
" subl %t0, %a1, %t0;" // Subtract n from value
" or %t0, %zero, %v0;" // set new value for return.
" stl_c %t0, (%a0);" // Save new value into *pNum
" beq %t0, 10b;" // Retry if sequence failed
, pNum, n);
}
#define HXAtomicIncINT32(p) HXAtomicIncRetINT32((p))
#define HXAtomicDecINT32(p) HXAtomicDecRetINT32((p))
#define HXAtomicAddINT32(p,n) HXAtomicAddRetINT32((p),(n))
#define HXAtomicSubINT32(p,n) HXAtomicSubRetINT32((p),(n))
#define HXAtomicIncUINT32(p) HXAtomicIncRetUINT32((p))
#define HXAtomicDecUINT32(p) HXAtomicDecRetUINT32((p))
#define HXAtomicAddUINT32(p,n) HXAtomicAddRetUINT32((p),(n))
#define HXAtomicSubUINT32(p,n) HXAtomicSubRetUINT32((p),(n))
/***********************************************************************
* AIX / PowerPC (Native compiler)
*
* Implementation Notes:
*
* XXXDC: The xlc compiler is able to do inline asm for C but when I do
* it for C++ it crashes, so for now I have resorted to putting
* the asm in a seperate assembler routine. The way you inline with
* xlc/xlC is difficult to use, requiring the use of "#pragma mc_func".
*/
#elif defined (_AIX)
//defined in common/util/platform/aix/atomicops.s
#if defined(__cplusplus)
extern "C" {
#endif
INT32 _HXAtomicAddRetINT32 (INT32* pNum, INT32 lNum);
INT32 _HXAtomicSubRetINT32 (INT32* pNum, INT32 lNum);
UINT32 _HXAtomicAddRetUINT32 (UINT32* pNum, UINT32 ulNum);
UINT32 _HXAtomicSubRetUINT32 (UINT32* pNum, UINT32 ulNum);
#if defined(__cplusplus)
}
#endif
#define HXAtomicIncINT32(p) _HXAtomicAddRetINT32((p),(INT32)1)
#define HXAtomicDecINT32(p) _HXAtomicSubRetINT32((p),(INT32)1)
#define HXAtomicIncRetINT32(p) _HXAtomicAddRetINT32((p),(INT32)1)
#define HXAtomicDecRetINT32(p) _HXAtomicSubRetINT32((p),(INT32)1)
#define HXAtomicAddINT32(p,n) _HXAtomicAddRetINT32((p),(n))
#define HXAtomicSubINT32(p,n) _HXAtomicSubRetINT32((p),(n))
#define HXAtomicAddRetINT32(p,n) _HXAtomicAddRetINT32((p),(n))
#define HXAtomicSubRetINT32(p,n) _HXAtomicSubRetINT32((p),(n))
#define HXAtomicIncUINT32(p) _HXAtomicAddRetUINT32((p),(UINT32)1)
#define HXAtomicDecUINT32(p) _HXAtomicSubRetUINT32((p),(UINT32)1)
#define HXAtomicIncRetUINT32(p) _HXAtomicAddRetUINT32((p),(UINT32)1)
#define HXAtomicDecRetUINT32(p) _HXAtomicSubRetUINT32((p),(UINT32)1)
#define HXAtomicAddUINT32(p,n) _HXAtomicAddRetUINT32((p),(n))
#define HXAtomicSubUINT32(p,n) _HXAtomicSubRetUINT32((p),(n))
#define HXAtomicAddRetUINT32(p,n) _HXAtomicAddRetUINT32((p),(n))
#define HXAtomicSubRetUINT32(p,n) _HXAtomicSubRetUINT32((p),(n))
/***********************************************************************
* MAC / PowerPC (CW)
*
* Implementation Notes:
*
* This will need to be rewritten, probably, once we move away from CW to PB.
*
* Note: This is an imcompletely-defined platform, be aware that
* not all standard HXAtomic operators are defined!
*
*/
#elif defined(_MACINTOSH) && defined(__MWERKS__)
inline UINT32
HXAtomicIncRetUINT32(register UINT32* pNum)
{
register UINT32 zeroOffset = 0;
register UINT32 temp;
asm
{
again:
lwarx temp, zeroOffset, pNum
addi temp, temp, 1
stwcx. temp, zeroOffset, pNum
bne- again
}
return temp;
}
inline UINT32
HXAtomicDecRetUINT32(register UINT32* pNum)
{
register UINT32 zeroOffset = 0;
register UINT32 temp;
asm
{
again:
lwarx temp, zeroOffset, pNum
subi temp, temp, 1
stwcx. temp, zeroOffset, pNum
bne- again
}
return temp;
}
/***********************************************************************
* MAC / PowerPC (PB)
*
* Implementation Notes:
*
* Use the atomic operations exposed by DriverSynchronization.h
*
* Note: This is an imcompletely-defined platform, be aware that
* not all standard HXAtomic operators are defined!
*
*/
#elif defined(_MACINTOSH) || defined(_MAC_UNIX)
inline UINT32
HXAtomicIncRetUINT32(UINT32* pNum)
{
return (UINT32)(IncrementAtomic((SInt32*)pNum) + 1);
}
inline UINT32
HXAtomicDecRetUINT32(UINT32* pNum)
{
return (UINT32)(DecrementAtomic((SInt32*)pNum) - 1);
}
/***********************************************************************
* Linux / PowerPC
*
* Implementation Notes:
*
* Use PowerPC load exclusive and store exclusive instructions
*
*/
#elif defined(_LINUX) && defined(__powerpc__)
inline UINT32
HXAtomicIncRetUINT32(UINT32* pNum)
{
volatile UINT32 result;
__asm__ __volatile__ (
"1: lwarx %0, 0, %2;\n"
" addi %0, %0, 1;\n"
" stwcx. %0, 0, %2;\n"
" bne- 1b;"
: "=r" (result)
: "0" (result), "r" (pNum)
: "cc", "memory"
);
return result;
}
inline UINT32
HXAtomicDecRetUINT32(UINT32* pNum)
{
volatile UINT32 result;
__asm__ __volatile__ (
"1: lwarx %0, 0, %2;\n"
" subi %0, %0, 1;\n"
" stwcx. %0, 0, %2;\n"
" bne- 1b;"
: "=r" (result)
: "0" (result), "r" (pNum)
: "cc", "memory"
);
return result;
}
/***********************************************************************
* Generic
*
* Implementation Notes:
*
* This should work on any platform with a HXMutex-style mutex.
* It allocates a pool of mutexes and hashes the int pointers
* to one of the mutexes. Since the mutexes are held for
* such a short time, only long enough to increment an int,
* collisions should be extremely rare and this should work fine,
* although it is probably less fast than the extra-high-performance
* atomic operators provided above. You need to link in atomic.cpp
* to get HXAtomic::m_pLocks defined.
*
* Basic design of the mutex-based lock-pool implementation:
* At startup, allocate an array of N mutexes (where N is a power of 2).
* When a method is called, hash the int pointer to one of the locks.
* Lock this mutex.
* Modify the value.
* Unlock this mutex.
*
*
* Platform-specific notes:
* Any platforms that use this should be documented here!
* Why are you using the generic operators for this platform?
*
* HP-UX / HP-PA:
* This is used on the HP-PA processor since it doesn't provide the
* necessary assembler operators to implement proper atomic updates
* of ints. HP's mutex primitive seems pretty fast however, resulting
* in a workable solution.
*
* OpenBSD:
* The standard assembler on x86 can't handle the gcc/asm operators
* defined above, so we're using the lock-pool approach for now.
* This approach also makes it possible to support non-x86 OpenBSD
* builds more easily (someday).
*
*/
#elif defined(_HPUX) || defined(_OPENBSD)
#include "microsleep.h"
#include "hxcom.h"
#include "hxmutexlock.h"
class HXAtomic
{
public:
HXAtomic();
~HXAtomic();
void InitLockPool();
/* Users of the HXAtomic routines should *NEVER* call these directly.
* They should *ALWAYS* use the HXAtomicAddRetINT32-style macros instead.
*/
INT32 _AddRetINT32 (INT32* pNum, INT32 nNum);
UINT32 _AddRetUINT32 (UINT32* pNum, UINT32 ulNum);
INT32 _SubRetINT32 (INT32* pNum, INT32 nNum);
UINT32 _SubRetUINT32 (UINT32* pNum, UINT32 ulNum);
private:
void Lock (HX_MUTEX pLock);
void Unlock (HX_MUTEX pLock);
HX_MUTEX* m_pLocks;
};
extern HXAtomic g_AtomicOps; //in common/util/atomicops.cpp
#define HXAtomicIncINT32(p) g_AtomicOps._AddRetINT32((p),(INT32)1)
#define HXAtomicDecINT32(p) g_AtomicOps._SubRetINT32((p),(INT32)1)
#define HXAtomicIncRetINT32(p) g_AtomicOps._AddRetINT32((p),(INT32)1)
#define HXAtomicDecRetINT32(p) g_AtomicOps._SubRetINT32((p),(INT32)1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -