atomicbase.h
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:53k
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: RCSL 1.0/RPSL 1.0
- *
- * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
- *
- * The contents of this file, and the files included with this file, are
- * subject to the current version of the RealNetworks Public Source License
- * Version 1.0 (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the RealNetworks Community Source License Version 1.0
- * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
- * in which case the RCSL will apply. You may also obtain the license terms
- * directly from RealNetworks. You may not use this file except in
- * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
- * applicable to this file, the RCSL. Please see the applicable RPSL or
- * RCSL for the rights, obligations and limitations governing use of the
- * contents of the file.
- *
- * This file is part of the Helix DNA Technology. RealNetworks is the
- * developer of the Original Code and owns the copyrights in the portions
- * it created.
- *
- * This file, and the files included with this file, is distributed and made
- * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- *
- * Technology Compatibility Kit Test Suite(s) Location:
- * http://www.helixcommunity.org/content/tck
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
- /***********************************************************************
- * THIS CODE IS HIGHLY CRITICAL TO THE SERVER'S STABILITY!!!
- * DO NOT MAKE CHANGES TO THE ATOMIC OPERATORS OR TO THE
- * MUTEX CODE WITHOUT A SERVER TEAM CODE-REVIEW! (dev@helix-server)
- */
- /****************************************************************************
- * $Id: atomicbase.h,v 1.23.2.2 2004/01/26 23:46:02 rggammon Exp $
- *
- * atomicbase.h - Defines several atomic operations
- *
- * See server/common/util/pub/servatomic.h for broader platform support.
- * Also conditionally overrides InterlockedIncrement/Decrement
- * via USE_HX_ATOMIC_INTERLOCKED_INC_DEC.
- *
- *
- ***********************************************************************
- *
- * Defines:
- *
- * void HXAtomicIncINT32(INT32* p) -- Increment *p
- * void HXAtomicDecINT32(INT32* p) -- Decrement *p
- * void HXAtomicAddINT32(INT32* p, INT32 n) -- Increment *p by n
- * void HXAtomicSubINT32(INT32* p, INT32 n) -- Decrement *p by n
- * INT32 HXAtomicIncRetINT32(INT32* p) -- Increment *p and return it
- * INT32 HXAtomicDecRetINT32(INT32* p) -- Decrement *p and return it
- * INT32 HXAtomicAddRetINT32(INT32* p, INT32 n)-- Increment *p by n, return it
- * INT32 HXAtomicSubRetINT32(INT32* p, INT32 n)-- Increment *p by n, return it
- *
- *
- * There are also UINT32 versions:
- *
- * void HXAtomicIncUINT32(UINT32* p)
- * void HXAtomicDecUINT32(UINT32* p)
- * void HXAtomicAddUINT32(UINT32* p, UINT32 n)
- * void HXAtomicSubUINT32(UINT32* p, UINT32 n)
- * UINT32 HXAtomicIncRetUINT32(UINT32* p)
- * UINT32 HXAtomicDecRetUINT32(UINT32* p)
- * UINT32 HXAtomicAddRetUINT32(UINT32* p, UINT32 n)
- * UINT32 HXAtomicSubRetUINT32(UINT32* p, UINT32 n)
- *
- ***********************************************************************
- *
- * TODO:
- * Add INT64 versions
- * Obsolete the 0x80000000-based Solaris implementation entirely.
- *
- ***********************************************************************/
- #ifndef _ATOMICBASE_H_
- #define _ATOMICBASE_H_
- /***********************************************************************
- * Sun Solaris / SPARC (Native compiler)
- *
- * Implementation Notes:
- * This uses inline assembly from server/common/util/platform/solaris/atomicops.il
- * Note: Sparc/gcc is in include/atomicbase.h
- */
- #if defined (_SOLARIS) && !defined (__GNUC__)
- #if defined(__cplusplus)
- extern "C" {
- #endif
- //UINT32 _HXAtomicIncRetUINT32 (UINT32* pNum);
- //UINT32 _HXAtomicDecRetUINT32 (UINT32* pNum);
- UINT32 _HXAtomicAddRetUINT32 (UINT32* pNum, UINT32 ulNum);
- UINT32 _HXAtomicSubRetUINT32 (UINT32* pNum, UINT32 ulNum);
- #if defined(__cplusplus)
- }
- #endif
- #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))
- inline void HXAtomicIncINT32(INT32* p) { HXAtomicIncUINT32((UINT32*)p); }
- inline void HXAtomicDecINT32(INT32* p) { HXAtomicDecUINT32((UINT32*)p); }
- inline void HXAtomicAddINT32(INT32* p, INT32 n) { HXAtomicAddUINT32((UINT32*)p, (UINT32)n); }
- inline void HXAtomicSubINT32(INT32* p, INT32 n) { HXAtomicSubUINT32((UINT32*)p, (UINT32)n); }
- inline INT32 HXAtomicIncRetINT32(INT32* p) { return HXAtomicIncRetUINT32((UINT32*)p); }
- inline INT32 HXAtomicDecRetINT32(INT32* p) { return HXAtomicDecRetUINT32((UINT32*)p); }
- inline INT32 HXAtomicAddRetINT32(INT32* p, INT32 n) { return HXAtomicAddRetUINT32((UINT32*)p, (UINT32)n); }
- inline INT32 HXAtomicSubRetINT32(INT32* p, INT32 n) { return HXAtomicSubRetUINT32((UINT32*)p, (UINT32)n); }
- /***********************************************************************
- * Sun Solaris / SPARC (gcc)
- *
- * Implementation Notes:
- * The sparc method of pipelining and use of "delay slots" requires
- * the nop's. Be extra careful modifying these routines!
- *
- * This implementation sacrifices being able to store the value
- * 0x800000000 in the INT32 value, which is a special "busy" marker value.
- * Since these are intended for use primarily with AddRef/Release and
- * resource usage counters, this should be acceptable for now. If a counter
- * is incremented to the point it would conflict with the flag, it is
- * incremented one more to hop over it. The same in reverse for decrement.
- * This is far from ideal, however... See the inline-assembly file
- * server/common/util/platform/solaris/mutex_setbit.il for *much*
- * better implementations using newer sparc assembly operators.
- *
- * Basic design of the flag-based implementation:
- * 1. Load a register with 0x80000000
- * 2. _atomically_ swap it with the INT32 (critical!)
- * 3. Compare what we got with 0x80000000
- * 4. Branch if equal to #2
- * 5. Increment (or decrement) the result
- * 6. Compare to 0x80000000
- * 7. Branch if equal to #5
- * 8. Save the new value to the INT32's location in memory
- * 9. Return new INT32 result if required
- *
- * This implementation primarily exists due to limitations in the ancient
- * version of gcc we used to use on Solaris (2.7.2.3), and more modern
- * gcc's can probably handle assembly more like what's used in Sun's
- * Native compiler version.
- *
- */
- #elif defined (__sparc__) && defined (__GNUC__)
- /* Increment by 1 */
- inline void
- HXAtomicIncUINT32(UINT32* pNum)
- {
- __asm__ __volatile__(
- "1: swap [%0], %2; ! Swap *pNum and %2n"
- " nop; ! delay slot...n"
- " cmp %2, %1; ! Is someone else using pNum?n"
- " be 1b; ! If so, retry...n"
- " nop; ! delay slot...yawnn"
- "2: inc %2; ! Increment %2n"
- " cmp %2, %1; ! check for overflown"
- " be 2b; ! if so, inc againn"
- " nop; ! but this means a delay, sighn"
- " st %2, [%0]; ! Save new value into *pNumn"
- : /* no output */
- : "r" (pNum), "r" (0x80000000), "r" (0x80000000)
- : "cc", "memory"
- );
- }
- /* Decrement by 1 */
- inline void
- HXAtomicDecUINT32(UINT32* pNum)
- {
- __asm__ __volatile__(
- "1: swap [%0], %2; ! Swap *pNum and %2n"
- " nop; ! delay slot...n"
- " cmp %2, %1; ! Is someone else using pNum?n"
- " be 1b; ! If so, retry...n"
- " nop; ! delay slot...yawnn"
- "2: dec %2; ! Increment %2n"
- " cmp %2, %1; ! check for overflown"
- " be 2b; ! if so, dec againn"
- " nop; ! but this means a delay, sighn"
- " st %2, [%0]; ! Save new value into *pNumn"
- : /* no output */
- : "r" (pNum), "r" (0x80000000), "r" (0x80000000)
- : "cc", "memory"
- );
- }
- /* Increment by 1 and return new value */
- inline UINT32
- HXAtomicIncRetUINT32(UINT32* pNum)
- {
- volatile UINT32 ulRet;
- __asm__ __volatile__(
- " mov %2, %0; ! Copy %2 to %0 n"
- "1: swap [%1], %0; ! Swap *pNum and %0n"
- " nop; ! delay slot...n"
- " cmp %0, %2; ! Is someone else using pNum?n"
- " be 1b; ! If so, retry...n"
- " nop; ! delay slot...yawnn"
- "2: inc %0; ! Increment %0n"
- " cmp %0, %2; ! check for overflown"
- " be 2b; ! if so, inc againn"
- " nop; ! but this means a delay, sighn"
- " st %0, [%1]; ! Save new value into *pNumn"
- : "=r" (ulRet)
- : "r" (pNum), "r" (0x80000000), "0" (ulRet)
- : "cc", "memory"
- );
- return ulRet;
- }
- /* Decrement by 1 and return new value */
- inline UINT32
- HXAtomicDecRetUINT32(UINT32* pNum)
- { volatile UINT32 ulRet;
- __asm__ __volatile__(
- " mov %2, %0; ! Copy %2 to %0 n"
- "1: swap [%1], %0; ! Swap *pNum and %0n"
- " nop; ! delay slot...n"
- " cmp %0, %2; ! Is someone else using pNum?n"
- " be 1b; ! If so, retry...n"
- " nop; ! delay slot...yawnn"
- "2: dec %0; ! Decrement %0n"
- " cmp %0, %2; ! check for overflown"
- " be 2b; ! if so, dec againn"
- " nop; ! but this means a delay, sighn"
- " st %0, [%1]; ! Save new value into *pNumn"
- : "=r" (ulRet)
- : "r" (pNum), "r" (0x80000000), "0" (ulRet)
- : "cc", "memory"
- );
- return ulRet;
- }
- /* Add n */
- inline void
- HXAtomicAddUINT32(UINT32* pNum, UINT32 ulNum)
- {
- __asm__ __volatile__(
- "1: swap [%0], %2; ! Swap *pNum and %2n"
- " nop; ! delay slot...n"
- " cmp %2, %1; ! Is someone else using pNum?n"
- " be 1b; ! If so, retry...n"
- " nop; ! delay slot...yawnn"
- " add %2, %3, %2; ! Add ulNum to %2n"
- " cmp %2, %1; ! check for overflown"
- " bne 2f; ! if not, skip to the endn"
- " nop; ! but this means a delay, sighn"
- " inc %2; ! skip marker valuen"
- "2: st %2, [%0]; ! Save new value into *pNumn"
- : /* no output */
- : "r" (pNum), "r" (0x80000000), "r" (0x80000000), "r" (ulNum)
- : "cc", "memory"
- );
- }
- /* Subtract n */
- inline void
- HXAtomicSubUINT32(UINT32* pNum, UINT32 ulNum)
- {
- __asm__ __volatile__(
- "1: swap [%0], %2; ! Swap *pNum and %2n"
- " nop; ! delay slot...n"
- " cmp %2, %1; ! Is someone else using pNum?n"
- " be 1b; ! If so, retry...n"
- " nop; ! delay slot...yawnn"
- " sub %2, %3, %2; ! Subtract ulNum to %2n"
- " cmp %2, %1; ! check for overflown"
- " bne 2f; ! if not, skip to the endn"
- " nop; ! but this means a delay, sighn"
- " inc %2; ! skip marker valuen"
- "2: st %2, [%0]; ! Save new value into *pNumn"
- : /* no output */
- : "r" (pNum), "r" (0x80000000), "r" (0x80000000), "r" (ulNum)
- : "cc", "memory"
- );
- }
- /* Add n and return new value */
- inline UINT32
- HXAtomicAddRetUINT32(UINT32* pNum, UINT32 ulNum)
- {
- volatile UINT32 ulRet;
- __asm__ __volatile__(
- " mov %2, %0 ! Copy %2 to %0 n"
- "1: swap [%1], %0; ! Swap *pNum and %0n"
- " nop; ! delay slot...n"
- " cmp %0, %2; ! Is someone else using pNum?n"
- " be 1b; ! If so, retry...n"
- " nop; ! delay slot...yawnn"
- " add %0, %3, %0; ! Add ulNum to %0n"
- " cmp %0, %2; ! check for overflown"
- " bne 2f; ! if not, skip to the endn"
- " nop; ! but this means a delay, sighn"
- " inc %0; ! skip marker valuen"
- "2: st %0, [%1]; ! Save new value into *pNumn"
- : "=r" (ulRet)
- : "r" (pNum), "r" (0x80000000), "r" (ulNum), "0" (ulRet)
- : "cc", "memory"
- );
- return ulRet;
- }
- /* Subtract n and return new value */
- inline UINT32
- HXAtomicSubRetUINT32(UINT32* pNum, UINT32 ulNum)
- { volatile UINT32 ulRet;
- __asm__ __volatile__(
- " mov %2, %0 ! Copy %2 to %0 n"
- "1: swap [%1], %0; ! Swap *pNum and %0n"
- " nop; ! delay slot...n"
- " cmp %0, %2; ! Is someone else using pNum?n"
- " be 1b; ! If so, retry...n"
- " nop; ! delay slot...yawnn"
- " sub %0, %3, %0; ! Sub ulNum from %0n"
- " cmp %0, %2; ! check for overflown"
- " bne 2f; ! if not, skip to the endn"
- " nop; ! but this means a delay, sighn"
- " dec %0; ! skip marker valuen"
- "2: st %0, [%1]; ! Save new value into *pNumn"
- : "=r" (ulRet)
- : "r" (pNum), "r" (0x80000000), "r" (ulNum), "0" (ulRet)
- : "cc", "memory"
- );
- return ulRet;
- }
- inline void HXAtomicIncINT32(INT32* p) { HXAtomicIncUINT32((UINT32*)p); }
- inline void HXAtomicDecINT32(INT32* p) { HXAtomicDecUINT32((UINT32*)p); }
- inline void HXAtomicAddINT32(INT32* p, INT32 n) { HXAtomicAddUINT32((UINT32*)p, (UINT32)n); }
- inline void HXAtomicSubINT32(INT32* p, INT32 n) { HXAtomicSubUINT32((UINT32*)p, (UINT32)n); }
- inline INT32 HXAtomicIncRetINT32(INT32* p) { return HXAtomicIncRetUINT32((UINT32*)p); }
- inline INT32 HXAtomicDecRetINT32(INT32* p) { return HXAtomicDecRetUINT32((UINT32*)p); }
- inline INT32 HXAtomicAddRetINT32(INT32* p, INT32 n) { return HXAtomicAddRetUINT32((UINT32*)p, (UINT32)n); }
- inline INT32 HXAtomicSubRetINT32(INT32* p, INT32 n) { return HXAtomicSubRetUINT32((UINT32*)p, (UINT32)n); }
- /***********************************************************************
- * Windows / x86 (Visual C/C++)
- *
- * Implementation Notes:
- * 'xadd' is only available in the 486 series and later, not the 386.
- * There is no 'xsub' counterpart, you have to negate the operand
- * and use 'xadd'. Note the use of the 'lock' prefix to ensure
- * certain operations occur atomically.
- */
- #elif defined (_M_IX86) /* && _M_IX86 > 300 XXX wschildbach: disabled until the build system delivers the correct value */
- /* Increment by 1 */
- static __inline void
- HXAtomicIncUINT32(UINT32* pNum)
- {
- // register usage summary:
- // eax - pointer to the value we're modifying
- _asm
- {
- mov eax, pNum ; Load the pointer into a register
- lock inc dword ptr [eax] ; Atomically increment *pNum
- }
- }
- /* Decrement by 1 */
- static __inline void
- HXAtomicDecUINT32(UINT32* pNum)
- {
- // register usage summary:
- // eax - pointer to the value we're modifying
- _asm
- {
- mov eax, pNum ; Load the pointer into a register
- lock dec dword ptr [eax] ; Atomically decrement *pNum
- }
- }
- /* Increment by 1 and return new value */
- static __inline UINT32
- HXAtomicIncRetUINT32(UINT32* pNum)
- {
- volatile UINT32 ulRet;
- // register usage summary:
- // eax - pointer to the value we're modifying
- // ebx - work register
- _asm
- {
- mov eax, pNum ; Load the pointer into a register
- mov ebx, 0x1 ; Load increment amount into a register
- lock xadd dword ptr [eax], ebx ; Increment *pNum; ebx gets old value
- inc ebx ; Increment old value
- mov ulRet, ebx ; Set the return value
- }
- return ulRet;
- }
- /* Decrement by 1 and return new value */
- static __inline UINT32
- HXAtomicDecRetUINT32(UINT32* pNum)
- {
- volatile UINT32 ulRet;
- // register usage summary:
- // eax - pointer to the value we're modifying
- // ebx - work register
- // note: we increment by 0xffffffff to decrement by 1
- _asm
- {
- mov eax, pNum ; Load the pointer into a register
- mov ebx, 0xffffffff ; Load decrement amount into a register
- lock xadd dword ptr [eax], ebx ; Decrement *pNum; ebx gets old value
- dec ebx ; decrement old value
- mov ulRet, ebx ; Set the return value
- }
- return ulRet;
- }
- /* Add n */
- static __inline void
- HXAtomicAddUINT32(UINT32* pNum, UINT32 ulNum)
- {
- // register usage summary:
- // eax - pointer to the value we're modifying
- // ebx - work register
- _asm
- {
- mov eax, pNum ; Load the pointer into a register
- mov ebx, ulNum ; Load increment amount into a register
- lock add dword ptr [eax], ebx ; Increment *pNum by ulNum
- }
- }
- /* Subtract n */
- static __inline void
- HXAtomicSubUINT32(UINT32* pNum, UINT32 ulNum)
- {
- // register usage summary:
- // eax - pointer to the value we're modifying
- // ebx - work register
- _asm
- {
- mov eax, pNum ; Load the pointer into a register
- mov ebx, ulNum ; Load increment amount into a register
- lock sub dword ptr [eax], ebx ; Atomically decrement *pNum by ulNum
- }
- }
- /* Add n and return new value */
- static __inline UINT32
- HXAtomicAddRetUINT32(UINT32* pNum, UINT32 ulNum)
- {
- volatile UINT32 ulRet;
- // register usage summary:
- // eax - pointer to the value we're modifying
- // ebx - work register
- // ecx - work register #2
- _asm
- {
- mov eax, pNum ; Load the pointer into a register
- mov ebx, ulNum ; Load increment amount into a register
- mov ecx, ebx ; copy ebx into ecx
- lock xadd dword ptr [eax], ecx ; Increment *pNum; ecx gets old value
- add ecx, ebx ; Add ulNum to it
- mov ulRet, ecx ; save result in ulRet
- }
- return ulRet;
- }
- /* Subtract n and return new value */
- static __inline UINT32
- HXAtomicSubRetUINT32(UINT32* pNum, UINT32 ulNum)
- {
- volatile UINT32 ulRet;
- // register usage summary:
- // eax - pointer to the value we're modifying
- // ebx - work register
- // ecx - work register #2
- _asm
- {
- mov eax, pNum ; Load the pointer into a register
- mov ebx, ulNum ; Load increment amount into a register
- mov ecx, 0x0 ; zero out ecx
- sub ecx, ebx ; compute -(ulNum), saving in ecx
- lock xadd dword ptr [eax], ecx ; Decrement *pNum; ecx gets old value
- sub ecx, ebx ; subtract ulNum from it
- mov ulRet, ecx ; save result in ulRet
- }
- return ulRet;
- }
- static __inline void HXAtomicIncINT32(INT32* p) { HXAtomicIncUINT32((UINT32*)p); }
- static __inline void HXAtomicDecINT32(INT32* p) { HXAtomicDecUINT32((UINT32*)p); }
- static __inline void HXAtomicAddINT32(INT32* p, INT32 n) { HXAtomicAddUINT32((UINT32*)p, (UINT32)n); }
- static __inline void HXAtomicSubINT32(INT32* p, INT32 n) { HXAtomicSubUINT32((UINT32*)p, (UINT32)n); }
- static __inline INT32 HXAtomicIncRetINT32(INT32* p) { return HXAtomicIncRetUINT32((UINT32*)p); }
- static __inline INT32 HXAtomicDecRetINT32(INT32* p) { return HXAtomicDecRetUINT32((UINT32*)p); }
- static __inline INT32 HXAtomicAddRetINT32(INT32* p, INT32 n) { return HXAtomicAddRetUINT32((UINT32*)p, (UINT32)n); }
- static __inline INT32 HXAtomicSubRetINT32(INT32* p, INT32 n) { return HXAtomicSubRetUINT32((UINT32*)p, (UINT32)n); }
- /***********************************************************************
- * Intel x86 (gcc) / Unix -- i486 and higher
- *
- * Implementation Notes:
- * 'xadd' is only available in the 486 series and later, not the 386.
- * There is no 'xsub' counterpart, you have to negate the operand
- * and use 'xadd'. Note the use of the 'lock' prefix to ensure
- * certain operations occur atomically.
- *
- * OpenBSD is excluded since the standard assembler on x86 systems
- * can't handle the xadd instruction.
- *
- */
- #elif defined(__GNUC__) && !defined(_OPENBSD) &&
- (__GNUC__>2 || (__GNUC__==2 && __GNUC_MINOR__>=95)) &&
- ( defined (__i486__) || defined (__i586__) || defined (__i686__) ||
- defined (__pentium__) || defined (__pentiumpro__))
- /* Increment by 1 */
- static __inline__ void
- HXAtomicIncUINT32(UINT32* pNum)
- {
- __asm__ __volatile__(
- "lock incl (%0);" // atomically add 1 to *pNum
- : /* no output */
- : "r" (pNum)
- : "cc", "memory"
- );
- }
- /* Decrement by 1 */
- static __inline__ void
- HXAtomicDecUINT32(UINT32* pNum)
- {
- __asm__ __volatile__(
- "lock decl (%0);" // atomically add -1 to *pNum
- : /* no output */
- : "r" (pNum)
- : "cc", "memory"
- );
- }
- /* Increment by 1 and return new value */
- static __inline__ UINT32
- HXAtomicIncRetUINT32(UINT32* pNum)
- {
- volatile UINT32 ulRet;
- __asm__ __volatile__(
- "lock xaddl %0, (%1);" // atomically add 1 to *pNum
- " inc %0;" // old value in %0, increment it
- : "=r" (ulRet)
- : "r" (pNum), "0" (0x1)
- : "cc", "memory"
- );
- return ulRet;
- }
- /* Decrement by 1 and return new value */
- static __inline__ UINT32
- HXAtomicDecRetUINT32(UINT32* pNum)
- {
- volatile UINT32 ulRet;
- __asm__ __volatile__(
- "lock xaddl %0, (%1);" // atomically add -1 to *pNum
- " dec %0;" // old value in %0, decrement it
- : "=r" (ulRet)
- : "r" (pNum), "0" (-1)
- : "cc", "memory"
- );
- return ulRet;
- }
- /* Add n */
- static __inline__ void
- HXAtomicAddUINT32(UINT32* pNum, UINT32 ulNum)
- {
- __asm__ __volatile__(
- "lock addl %1, (%0);" // atomically add ulNum to *pNum
- : /* no output */
- : "r" (pNum), "r" (ulNum)
- : "cc", "memory"
- );
- }
- /* Subtract n */
- static __inline__ void
- HXAtomicSubUINT32(UINT32* pNum, UINT32 ulNum)
- {
- __asm__ __volatile__(
- "lock subl %1, (%0);" // atomically add ulNum to *pNum
- : /* no output */
- : "r" (pNum), "r" (ulNum)
- : "cc", "memory"
- );
- }
- /* Add n and return new value */
- static __inline__ UINT32
- HXAtomicAddRetUINT32(UINT32* pNum, UINT32 ulNum)
- {
- volatile UINT32 ulRet;
- __asm__ __volatile__(
- " mov %2, %0;" // copy ulNum into %0
- "lock xaddl %0, (%1);" // atomically add ulNum to *pNum
- " add %2, %0;" // old value in %0, add ulNum
- : "=r" (ulRet)
- : "r" (pNum), "r" (ulNum), "0" (0)
- : "cc", "memory"
- );
- return ulRet;
- }
- /* Subtract n and return new value */
- static __inline__ UINT32
- HXAtomicSubRetUINT32(UINT32* pNum, UINT32 ulNum)
- {
- volatile UINT32 ulRet;
- __asm__ __volatile__(
- " sub %2, %0;" // negate ulNum, saving in %0
- "lock xaddl %0, (%1);" // atomically add -(ulNum) to *pNum
- " sub %2, %0;" // old value in %0, subtract ulNum
- : "=r" (ulRet)
- : "r" (pNum), "r" (ulNum), "0" (0)
- : "cc", "memory"
- );
- return ulRet;
- }
- static __inline__ void HXAtomicIncINT32(INT32* p) { HXAtomicIncUINT32((UINT32*)p); }
- static __inline__ void HXAtomicDecINT32(INT32* p) { HXAtomicDecUINT32((UINT32*)p); }
- static __inline__ void HXAtomicAddINT32(INT32* p, INT32 n) { HXAtomicAddUINT32((UINT32*)p, (UINT32)n); }
- static __inline__ void HXAtomicSubINT32(INT32* p, INT32 n) { HXAtomicSubUINT32((UINT32*)p, (UINT32)n); }
- static __inline__ INT32 HXAtomicIncRetINT32(INT32* p) { return HXAtomicIncRetUINT32((UINT32*)p); }
- static __inline__ INT32 HXAtomicDecRetINT32(INT32* p) { return HXAtomicDecRetUINT32((UINT32*)p); }
- static __inline__ INT32 HXAtomicAddRetINT32(INT32* p, INT32 n) { return HXAtomicAddRetUINT32((UINT32*)p, (UINT32)n); }
- static __inline__ INT32 HXAtomicSubRetINT32(INT32* p, INT32 n) { return HXAtomicSubRetUINT32((UINT32*)p, (UINT32)n); }
- /***********************************************************************
- * HP-UX / IA64 (Native compiler)
- *
- * Implementation Notes:
- * A work-in-progress...
- */
- #elif defined(_HPUX) && defined(_IA64)
- #if defined(__cplusplus)
- extern "C" {
- #endif
- UINT32 _HXAtomicIncRetUINT32 (UINT32* pNum);
- UINT32 _HXAtomicDecRetUINT32 (UINT32* pNum);
- UINT32 _HXAtomicAddRetUINT32 (UINT32* pNum, UINT32 ulNum);
- UINT32 _HXAtomicSubRetUINT32 (UINT32* pNum, UINT32 ulNum);
- #if defined(__cplusplus)
- }
- #endif
- #define HXAtomicIncINT32(p) _HXAtomicIncRetUINT32((UINT32*)(p))
- #define HXAtomicDecINT32(p) _HXAtomicDecRetUINT32((UINT32*)(p))
- #define HXAtomicIncRetINT32(p) _HXAtomicIncRetUINT32((UINT32*)(p))
- #define HXAtomicDecRetINT32(p) _HXAtomicDecRetUINT32((UINT32*)(p))
- #define HXAtomicAddINT32(p,n) _HXAtomicAddRetUINT32((UINT32*)(p),(INT32)(n))
- #define HXAtomicSubINT32(p,n) _HXAtomicSubRetUINT32((UINT32*)(p),(INT32)(n))
- #define HXAtomicAddRetINT32(p,n) _HXAtomicAddRetUINT32((UINT32*)(p),(INT32)(n))
- #define HXAtomicSubRetINT32(p,n) _HXAtomicSubRetUINT32((UINT32*)(p),(INT32)(n))
- #define HXAtomicIncUINT32(p) _HXAtomicIncRetUINT32((p))
- #define HXAtomicDecUINT32(p) _HXAtomicDecRetUINT32((p))
- #define HXAtomicIncRetUINT32(p) _HXAtomicIncRetUINT32((p))
- #define HXAtomicDecRetUINT32(p) _HXAtomicDecRetUINT32((p))
- #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))
- /***********************************************************************
- * Tru64 (OSF1) / Alpha (Native compiler)
- *
- * Implementation Notes:
- *
- * The Alpha CPU provides instructions to load-lock a value,
- * modify it, and attempt to write it back. If the value has
- * been modified by someone else since the load-lock occured,
- * the write will fail and you can check the status code to
- * know whether you need to retry or not.
- *
- */
- #elif defined (__alpha)
- #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)
- #define HXAtomicAddRetINT32(p,n) g_AtomicOps._AddRetINT32((p),(n))
- #define HXAtomicSubRetINT32(p,n) g_AtomicOps._SubRetINT32((p),(n))
- #define HXAtomicAddINT32(p,n) g_AtomicOps._AddRetINT32((p),(n))
- #define HXAtomicSubINT32(p,n) g_AtomicOps._SubRetINT32((p),(n))
- #define HXAtomicIncUINT32(p) g_AtomicOps._AddRetUINT32((p),(UINT32)1)
- #define HXAtomicDecUINT32(p) g_AtomicOps._SubRetUINT32((p),(UINT32)1)
- #define HXAtomicIncRetUINT32(p) g_AtomicOps._AddRetUINT32((p),(UINT32)1)
- #define HXAtomicDecRetUINT32(p) g_AtomicOps._SubRetUINT32((p),(UINT32)1)
- #define HXAtomicAddRetUINT32(p,n) g_AtomicOps._AddRetUINT32((p),(n))
- #define HXAtomicSubRetUINT32(p,n) g_AtomicOps._SubRetUINT32((p),(n))
- #define HXAtomicAddUINT32(p,n) g_AtomicOps._AddRetUINT32((p),(n))
- #define HXAtomicSubUINT32(p,n) g_AtomicOps._SubRetUINT32((p),(n))
- /***********************************************************************
- * SYMBIAN
- *
- * Implementation Notes:
- *
- * Note: This is an imcompletely-defined platform, be aware that
- * not all standard HXAtomic operators are defined!
- *
- */
- #elif defined(_SYMBIAN)
- /* Increment by 1 and return new value */
- inline INT32
- HXAtomicIncRetINT32(INT32* pNum)
- {
- return User::LockedInc(*((TInt*)pNum)) + 1;
- }
- /* Decrement by 1 and return new value */
- inline INT32
- HXAtomicDecRetINT32(INT32* pNum)
- {
- return User::LockedDec(*((TInt*)pNum)) - 1;
- }
- /* Increment by 1 and return new value */
- inline UINT32
- HXAtomicIncRetUINT32(UINT32* pNum)
- {
- return ((UINT32)User::LockedInc(*((TInt*)pNum))) + 1;
- }
- /* Decrement by 1 and return new value */
- inline UINT32
- HXAtomicDecRetUINT32(UINT32* pNum)
- {
- return ((UINT32)User::LockedDec(*((TInt*)pNum))) - 1;
- }
- #define HXAtomicIncINT32(p) HXAtomicIncRetINT32((p))
- #define HXAtomicDecINT32(p) HXAtomicDecRetINT32((p))
- #define HXAtomicIncUINT32(p) HXAtomicIncRetUINT32((p))
- #define HXAtomicDecUINT32(p) HXAtomicDecRetUINT32((p))
- #if 0
- /*
- * Add and subtract operations are not implemented
- * at this time because there isn't an easy way to
- * do it using the facilities provided by Symbian.
- * Assembly will likely be needed.
- */
- /* Add n and return new value */
- inline INT32
- HXAtomicAddRetINT32(INT32* pNum, INT32 n)
- {
- }
- /* Subtract n and return new value */
- inline INT32
- HXAtomicSubRetINT32(INT32* pNum, INT32 n)
- {
- }
- /* Add n and return new value */
- inline UINT32
- HXAtomicAddRetUINT32(UINT32* pNum, UINT32 n)
- {
- }
- /* Subtract n and return new value */
- inline UINT32
- HXAtomicSubRetUINT32(UINT32* pNum, UINT32 n)
- {
- }
- #define HXAtomicAddINT32(p,n) HXAtomicAddRetINT32((p),(n))
- #define HXAtomicSubINT32(p,n) HXAtomicSubRetINT32((p),(n))
- #define HXAtomicAddUINT32(p,n) HXAtomicAddRetUINT32((p),(n))
- #define HXAtomicSubUINT32(p,n) HXAtomicSubRetUINT32((p),(n))
- #endif
- /***********************************************************************
- * Linux / ARM (gcc)
- *
- * Implementation Notes:
- *
- * This implementation sacrifices being able to store the value
- * 0x800000000 in the INT32 value, which is a special "busy" marker value.
- * Since these are intended for use primarily with AddRef/Release and
- * resource usage counters, this should be acceptable for now. If a counter
- * is incremented to the point it would conflict with the flag, it is
- * incremented one more to hop over it. The same in reverse for decrement.
- *
- * Basic design of the flag-based implementation:
- * 1. Load a register with 0x80000000
- * 2. _atomically_ swap it with the INT32 (critical!)
- * 3. Compare what we got with 0x80000000
- * 4. Branch if equal to #2
- * 5. Increment (or decrement) the result
- * 6. Compare to 0x80000000
- * 7. Increment (or decrement) again if equal
- * 8. Save the new value to the INT32's location in memory
- * 9. Return new INT32 result if required
- *
- */
- #elif defined (_ARM) && defined (__GNUC__)
- /* Increment by 1 */
- inline void
- HXAtomicIncUINT32(UINT32* pNum)
- {
- UINT32 ulTmp;
- __asm__ __volatile__(
- " mov %0, #0x80000000;n" /* Set ulTmp to 0x800000000 */
- "1: swp %0, %0, [%1];n" /* Swap *pNum and ulTmp */
- " cmp %0, #0x80000000;n" /* Is someone else using pNum? */
- " beq 1;n" /* If so, retry... */
- " add %0, %0, #1;n" /* Increment ulTmp */
- " cmp %0, #0x80000000;n" /* check for overflow */
- " addeq %0, %0, #1;n" /* if so, increment again */
- " str %0, [%1];n" /* Save new value into *pNum */
- : /* no output */
- : "r" (ulTmp), "r" (pNum)
- : "cc", "memory"
- );
- }
- /* Decrement by 1 */
- inline void
- HXAtomicDecUINT32(UINT32* pNum)
- {
- UINT32 ulTmp;
- __asm__ __volatile__(
- " mov %0, #0x80000000;n" /* Set ulTmp to 0x800000000 */
- "1: swp %0, %0, [%1];n" /* Swap *pNum and ulTmp */
- " cmp %0, #0x80000000;n" /* Is someone else using pNum? */
- " beq 1;n" /* If so, retry... */
- " sub %0, %0, #1;n" /* Decrement ulTmp */
- " cmp %0, #0x80000000;n" /* check for overflow */
- " subeq %0, %0, #1;n" /* if so, decrement again */
- " str %0, [%1];n" /* Save new value into *pNum */
- : /* no output */
- : "r" (ulTmp), "r" (pNum)
- : "cc", "memory"
- );
- }
- /* Increment by 1 and return new value */
- inline UINT32
- HXAtomicIncRetUINT32(UINT32* pNum)
- {
- volatile UINT32 ulRet;
- __asm__ __volatile__(
- " mov %0, #0x80000000;n" /* Set ulRet to 0x80000000 */
- "1: swp %0, %0, [%1];n" /* Swap *pNum and ulRet */
- " cmp %0, #0x80000000;n" /* Is someone else using pNum? */
- " beq 1;n" /* If so, retry... */
- " add %0, %0, #1;n" /* Increment ulRet */
- " cmp %0, #0x80000000;n" /* check for overflow */
- " addeq %0, %0, #1;n" /* if so, increment again */
- " str %0, [%1];n" /* Save new value into *pNum */
- : "=&r" (ulRet)
- : "r" (pNum)
- : "cc", "memory"
- );
- return ulRet;
- }
- /* Decrement by 1 and return new value */
- inline UINT32
- HXAtomicDecRetUINT32(UINT32* pNum)
- {
- volatile UINT32 ulRet;
- __asm__ __volatile__(
- " mov %0, #0x80000000;n" /* Set ulRet to 0x80000000 */
- "1: swp %0, %0, [%1];n" /* Swap *pNum and ulRet */
- " cmp %0, #0x80000000;n" /* Is someone else using pNum? */
- " beq 1;n" /* If so, retry... */
- " sub %0, %0, #1;n" /* Decrement ulRet */
- " cmp %0, #0x80000000;n" /* check for overflow */
- " subeq %0, %0, #1;n" /* if so, decrement again */
- " str %0, [%1];n" /* Save new value into *pNum */
- : "=&r" (ulRet)
- : "r" (pNum)
- : "cc", "memory"
- );
- return ulRet;
- }
- /* Add n */
- inline void
- HXAtomicAddUINT32(UINT32* pNum, UINT32 ulNum)
- {
- UINT32 ulTmp;
- __asm__ __volatile__(
- " mov %0, #0x80000000;n" /* Set ulTmp to 0x800000000 */
- "1: swp %0, %0, [%1];n" /* Swap *pNum and ulTmp */
- " cmp %0, #0x80000000;n" /* Is someone else using pNum? */
- " beq 1;n" /* If so, retry... */
- " add %0, %0, %2;n" /* Add ulNum to ulTmp */
- " cmp %0, #0x80000000;n" /* check for overflow */
- " addeq %0, %0, #1;n" /* if so, increment again */
- " str %0, [%1];n" /* Save new value into *pNum */
- : /* no output */
- : "r" (ulTmp), "r" (pNum), "r" (ulNum)
- : "cc", "memory"
- );
- }
- /* Subtract n */
- inline void
- HXAtomicSubUINT32(UINT32* pNum, UINT32 ulNum)
- {
- UINT32 ulTmp;
- __asm__ __volatile__(
- " mov %0, #0x80000000;n" /* Set ulTmp to 0x800000000 */
- "1: swp %0, %0, [%1];n" /* Swap *pNum and ulTmp */
- " cmp %0, #0x80000000;n" /* Is someone else using pNum? */
- " beq 1;n" /* If so, retry... */
- " sub %0, %0, %2;n" /* Subtract ulNum from ulTmp */
- " cmp %0, #0x80000000;n" /* check for overflow */
- " subeq %0, %0, #1;n" /* if so, decrement again */
- " str %0, [%1];n" /* Save new value into *pNum */
- : /* no output */
- : "r" (ulTmp), "r" (pNum), "r" (ulNum)
- : "cc", "memory"
- );
- }
- /* Add n and return new value */
- inline UINT32
- HXAtomicAddRetUINT32(UINT32* pNum, UINT32 ulNum)
- {
- volatile UINT32 ulRet;
- __asm__ __volatile__(
- " mov %0, #0x80000000;n" /* Set ulRet to 0x80000000 */
- "1: swp %0, %0, [%1];n" /* Swap *pNum and ulRet */
- " cmp %0, #0x80000000;n" /* Is someone else using pNum? */
- " beq 1;n" /* If so, retry... */
- " add %0, %0, %2;n" /* Add ulNum to ulRet */
- " cmp %0, #0x80000000;n" /* check for overflow */
- " addeq %0, %0, #1;n" /* if so, increment again */
- " str %0, [%1];n" /* Save new value into *pNum */
- : "=&r" (ulRet)
- : "r" (pNum) , "r" (ulNum)
- : "cc", "memory"
- );
- return ulRet;
- }
- /* Subtract n and return new value */
- inline UINT32
- HXAtomicSubRetUINT32(UINT32* pNum, UINT32 ulNum)
- {
- volatile UINT32 ulRet;
- __asm__ __volatile__(
- " mov %0, #0x80000000;n" /* Set ulRet to 0x80000000 */
- "1: swp %0, %0, [%1];n" /* Swap *pNum and ulRet */
- " cmp %0, #0x80000000;n" /* Is someone else using pNum? */
- " beq 1;n" /* If so, retry... */
- " sub %0, %0, %2;n" /* Subtract ulNum from ulRet */
- " cmp %0, #0x80000000;n" /* check for overflow */
- " subeq %0, %0, #1;n" /* if so, decrement again */
- " str %0, [%1];n" /* Save new value into *pNum */
- : "=&r" (ulRet)
- : "r" (pNum), "r" (ulNum)
- : "cc", "memory"
- );
- return ulRet;
- }
- inline void HXAtomicIncINT32(INT32* p) { HXAtomicIncUINT32((UINT32*)p); }
- inline void HXAtomicDecINT32(INT32* p) { HXAtomicDecUINT32((UINT32*)p); }
- inline void HXAtomicAddINT32(INT32* p, INT32 n) { HXAtomicAddUINT32((UINT32*)p, (UINT32)n); }
- inline void HXAtomicSubINT32(INT32* p, INT32 n) { HXAtomicSubUINT32((UINT32*)p, (UINT32)n); }
- inline INT32 HXAtomicIncRetINT32(INT32* p) { return HXAtomicIncRetUINT32((UINT32*)p); }
- inline INT32 HXAtomicDecRetINT32(INT32* p) { return HXAtomicDecRetUINT32((UINT32*)p); }
- inline INT32 HXAtomicAddRetINT32(INT32* p, INT32 n) { return HXAtomicAddRetUINT32((UINT32*)p, (UINT32)n); }
- inline INT32 HXAtomicSubRetINT32(INT32* p, INT32 n) { return HXAtomicSubRetUINT32((UINT32*)p, (UINT32)n); }
- /***********************************************************************
- * Add new platforms above here
- */
- #else
- //
- // Unsupported platform
- //
- # ifndef HELIX_CONFIG_DISABLE_ATOMIC_OPERATORS
- // Defining HELIX_CONFIG_DISABLE_ATOMIC_OPERATORS will use the ++ and --
- // operators in place of atomic operators in some places in the code. These
- // operators are not thread-safe, and should only be used in the intermediary
- // stages of porting.
- # error "You need to create atomic dec/inc opers for your platform or #define HELIX_CONFIG_DISABLE_ATOMIC_OPERATORS"
- # endif
- #endif
- /*************************************************************************/
- /*
- * Conditional override of InterlockedIncrement/Decrement
- *
- * Place this in your Umakefil/.pcf file to turn off atomic
- * InterlockedIncrement/Decrement on a per-module basis,
- * or place it in your umake profile for system-wide scope.
- * If this is defined you'll still have access to the underlying
- * HXAtomicxxx operators (if they exist for your platform),
- * just that the specific InterlockedIncrement/InterlockedDecrement
- * macros won't be defined to use them.
- */
- #if !defined (HELIX_CONFIG_DISABLE_ATOMIC_OPERATORS)
- #undef InterlockedIncrement
- #undef InterlockedDecrement
- // Since many classes (incorrectly) implement their refcount using LONG32
- // rather than the proper ULONG32, we have to use the typecast for things
- // to build on many platforms.
- #define InterlockedIncrement(p) HXAtomicIncRetUINT32((UINT32*)(p))
- #define InterlockedDecrement(p) HXAtomicDecRetUINT32((UINT32*)(p))
- #define HAVE_INTERLOCKED_INCREMENT //so hxcom.h doesn't redefine these to ++/--
- #endif /* !defined(HELIX_CONFIG_DISABLE_ATOMIC_OPERATORS) */
- #endif /* _ATOMICBASE_H_ */