📄 atomicbase.h
字号:
/* ***** 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 %2\n"
" nop; ! delay slot...\n"
" cmp %2, %1; ! Is someone else using pNum?\n"
" be 1b; ! If so, retry...\n"
" nop; ! delay slot...yawn\n"
"2: inc %2; ! Increment %2\n"
" cmp %2, %1; ! check for overflow\n"
" be 2b; ! if so, inc again\n"
" nop; ! but this means a delay, sigh\n"
" st %2, [%0]; ! Save new value into *pNum\n"
: /* 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 %2\n"
" nop; ! delay slot...\n"
" cmp %2, %1; ! Is someone else using pNum?\n"
" be 1b; ! If so, retry...\n"
" nop; ! delay slot...yawn\n"
"2: dec %2; ! Increment %2\n"
" cmp %2, %1; ! check for overflow\n"
" be 2b; ! if so, dec again\n"
" nop; ! but this means a delay, sigh\n"
" st %2, [%0]; ! Save new value into *pNum\n"
: /* 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 %0\n"
" nop; ! delay slot...\n"
" cmp %0, %2; ! Is someone else using pNum?\n"
" be 1b; ! If so, retry...\n"
" nop; ! delay slot...yawn\n"
"2: inc %0; ! Increment %0\n"
" cmp %0, %2; ! check for overflow\n"
" be 2b; ! if so, inc again\n"
" nop; ! but this means a delay, sigh\n"
" st %0, [%1]; ! Save new value into *pNum\n"
: "=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 %0\n"
" nop; ! delay slot...\n"
" cmp %0, %2; ! Is someone else using pNum?\n"
" be 1b; ! If so, retry...\n"
" nop; ! delay slot...yawn\n"
"2: dec %0; ! Decrement %0\n"
" cmp %0, %2; ! check for overflow\n"
" be 2b; ! if so, dec again\n"
" nop; ! but this means a delay, sigh\n"
" st %0, [%1]; ! Save new value into *pNum\n"
: "=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 %2\n"
" nop; ! delay slot...\n"
" cmp %2, %1; ! Is someone else using pNum?\n"
" be 1b; ! If so, retry...\n"
" nop; ! delay slot...yawn\n"
" add %2, %3, %2; ! Add ulNum to %2\n"
" cmp %2, %1; ! check for overflow\n"
" bne 2f; ! if not, skip to the end\n"
" nop; ! but this means a delay, sigh\n"
" inc %2; ! skip marker value\n"
"2: st %2, [%0]; ! Save new value into *pNum\n"
: /* 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 %2\n"
" nop; ! delay slot...\n"
" cmp %2, %1; ! Is someone else using pNum?\n"
" be 1b; ! If so, retry...\n"
" nop; ! delay slot...yawn\n"
" sub %2, %3, %2; ! Subtract ulNum to %2\n"
" cmp %2, %1; ! check for overflow\n"
" bne 2f; ! if not, skip to the end\n"
" nop; ! but this means a delay, sigh\n"
" inc %2; ! skip marker value\n"
"2: st %2, [%0]; ! Save new value into *pNum\n"
: /* 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 %0\n"
" nop; ! delay slot...\n"
" cmp %0, %2; ! Is someone else using pNum?\n"
" be 1b; ! If so, retry...\n"
" nop; ! delay slot...yawn\n"
" add %0, %3, %0; ! Add ulNum to %0\n"
" cmp %0, %2; ! check for overflow\n"
" bne 2f; ! if not, skip to the end\n"
" nop; ! but this means a delay, sigh\n"
" inc %0; ! skip marker value\n"
"2: st %0, [%1]; ! Save new value into *pNum\n"
: "=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 %0\n"
" nop; ! delay slot...\n"
" cmp %0, %2; ! Is someone else using pNum?\n"
" be 1b; ! If so, retry...\n"
" nop; ! delay slot...yawn\n"
" sub %0, %3, %0; ! Sub ulNum from %0\n"
" cmp %0, %2; ! check for overflow\n"
" bne 2f; ! if not, skip to the end\n"
" nop; ! but this means a delay, sigh\n"
" dec %0; ! skip marker value\n"
"2: st %0, [%1]; ! Save new value into *pNum\n"
: "=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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -