atomicbase.h
Upload User: dangjiwu
Upload Date: 2013-07-19
Package Size: 42019k
Code Size: 54k
Category:

Symbian

Development Platform:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: atomicbase.h,v 1.23.2.6 2004/07/09 01:45:08 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. /***********************************************************************
  50.  *  THIS CODE IS HIGHLY CRITICAL TO THE SERVER'S STABILITY!!!
  51.  *  DO NOT MAKE CHANGES TO THE ATOMIC OPERATORS OR TO THE
  52.  *  MUTEX CODE WITHOUT A SERVER TEAM CODE-REVIEW! (dev@helix-server)
  53.  */
  54. /****************************************************************************
  55.  *  $Id: atomicbase.h,v 1.23.2.6 2004/07/09 01:45:08 hubbe Exp $
  56.  *
  57.  *  atomicbase.h - Defines several atomic operations
  58.  * 
  59.  *  See server/common/util/pub/servatomic.h for broader platform support.
  60.  *  Also conditionally overrides InterlockedIncrement/Decrement
  61.  *  via USE_HX_ATOMIC_INTERLOCKED_INC_DEC.
  62.  *
  63.  *
  64.  ***********************************************************************
  65.  *
  66.  * Defines:
  67.  *
  68.  * void HXAtomicIncINT32(INT32* p)             -- Increment *p
  69.  * void HXAtomicDecINT32(INT32* p)             -- Decrement *p
  70.  * void HXAtomicAddINT32(INT32* p, INT32 n)    -- Increment *p by n 
  71.  * void HXAtomicSubINT32(INT32* p, INT32 n)    -- Decrement *p by n
  72.  * INT32 HXAtomicIncRetINT32(INT32* p)         -- Increment *p and return it
  73.  * INT32 HXAtomicDecRetINT32(INT32* p)         -- Decrement *p and return it
  74.  * INT32 HXAtomicAddRetINT32(INT32* p, INT32 n)-- Increment *p by n, return it
  75.  * INT32 HXAtomicSubRetINT32(INT32* p, INT32 n)-- Increment *p by n, return it
  76.  *
  77.  *
  78.  * There are also UINT32 versions:
  79.  *
  80.  * void HXAtomicIncUINT32(UINT32* p)
  81.  * void HXAtomicDecUINT32(UINT32* p)
  82.  * void HXAtomicAddUINT32(UINT32* p, UINT32 n)
  83.  * void HXAtomicSubUINT32(UINT32* p, UINT32 n)
  84.  * UINT32 HXAtomicIncRetUINT32(UINT32* p)
  85.  * UINT32 HXAtomicDecRetUINT32(UINT32* p)
  86.  * UINT32 HXAtomicAddRetUINT32(UINT32* p, UINT32 n)
  87.  * UINT32 HXAtomicSubRetUINT32(UINT32* p, UINT32 n)
  88.  *
  89.  ***********************************************************************
  90.  *
  91.  * TODO:
  92.  *   Add INT64 versions
  93.  *   Obsolete the 0x80000000-based Solaris implementation entirely.
  94.  *
  95.  ***********************************************************************/
  96. #ifndef _ATOMICBASE_H_
  97. #define _ATOMICBASE_H_
  98. /***********************************************************************
  99.  * Sun Solaris / SPARC (Native compiler)
  100.  *
  101.  * Implementation Notes:
  102.  * This uses inline assembly from server/common/util/platform/solaris/atomicops.il
  103.  * Note: Sparc/gcc is in include/atomicbase.h
  104.  */
  105. #if defined (_SOLARIS) && !defined (__GNUC__)
  106. #if defined(__cplusplus)
  107. extern "C" {
  108. #endif
  109.     //UINT32 _HXAtomicIncRetUINT32 (UINT32* pNum);
  110.     //UINT32 _HXAtomicDecRetUINT32 (UINT32* pNum);
  111.     UINT32 _HXAtomicAddRetUINT32 (UINT32* pNum, UINT32 ulNum);
  112.     UINT32 _HXAtomicSubRetUINT32 (UINT32* pNum, UINT32 ulNum);
  113. #if defined(__cplusplus)
  114. }
  115. #endif
  116. #define HXAtomicIncUINT32(p)      _HXAtomicAddRetUINT32((p),(UINT32)1)
  117. #define HXAtomicDecUINT32(p)      _HXAtomicSubRetUINT32((p),(UINT32)1)
  118. #define HXAtomicIncRetUINT32(p)   _HXAtomicAddRetUINT32((p),(UINT32)1)
  119. #define HXAtomicDecRetUINT32(p)   _HXAtomicSubRetUINT32((p),(UINT32)1)
  120. #define HXAtomicAddUINT32(p,n)    _HXAtomicAddRetUINT32((p),(n))
  121. #define HXAtomicSubUINT32(p,n)    _HXAtomicSubRetUINT32((p),(n))
  122. #define HXAtomicAddRetUINT32(p,n) _HXAtomicAddRetUINT32((p),(n))
  123. #define HXAtomicSubRetUINT32(p,n) _HXAtomicSubRetUINT32((p),(n))
  124. inline void HXAtomicIncINT32(INT32* p)              { HXAtomicIncUINT32((UINT32*)p); }
  125. inline void HXAtomicDecINT32(INT32* p)              { HXAtomicDecUINT32((UINT32*)p); }
  126. inline void HXAtomicAddINT32(INT32* p, INT32 n)     { HXAtomicAddUINT32((UINT32*)p, (UINT32)n); }
  127. inline void HXAtomicSubINT32(INT32* p, INT32 n)     { HXAtomicSubUINT32((UINT32*)p, (UINT32)n); }
  128. inline INT32 HXAtomicIncRetINT32(INT32* p)          { return HXAtomicIncRetUINT32((UINT32*)p); }
  129. inline INT32 HXAtomicDecRetINT32(INT32* p)          { return HXAtomicDecRetUINT32((UINT32*)p); }
  130. inline INT32 HXAtomicAddRetINT32(INT32* p, INT32 n) { return HXAtomicAddRetUINT32((UINT32*)p, (UINT32)n); }
  131. inline INT32 HXAtomicSubRetINT32(INT32* p, INT32 n) { return HXAtomicSubRetUINT32((UINT32*)p, (UINT32)n); }
  132. /***********************************************************************
  133.  * Sun Solaris / SPARC (gcc)
  134.  *
  135.  * Implementation Notes:
  136.  * The sparc method of pipelining and use of "delay slots" requires
  137.  * the nop's.  Be extra careful modifying these routines!
  138.  *
  139.  * This implementation sacrifices being able to store the value
  140.  * 0x800000000 in the INT32 value, which is a special "busy" marker value.
  141.  * Since these are intended for use primarily with AddRef/Release and
  142.  * resource usage counters, this should be acceptable for now.  If a counter
  143.  * is incremented to the point it would conflict with the flag, it is
  144.  * incremented one more to hop over it.  The same in reverse for decrement.
  145.  * This is far from ideal, however...  See the inline-assembly file
  146.  * server/common/util/platform/solaris/mutex_setbit.il for *much*
  147.  * better implementations using newer sparc assembly operators.
  148.  *
  149.  * Basic design of the flag-based implementation:
  150.  *   1. Load a register with 0x80000000
  151.  *   2. _atomically_ swap it with the INT32 (critical!)
  152.  *   3. Compare what we got with 0x80000000
  153.  *   4. Branch if equal to #2
  154.  *   5. Increment (or decrement) the result
  155.  *   6. Compare to 0x80000000
  156.  *   7. Branch if equal to #5
  157.  *   8. Save the new value to the INT32's location in memory
  158.  *   9. Return new INT32 result if required
  159.  *   
  160.  * This implementation primarily exists due to limitations in the ancient
  161.  * version of gcc we used to use on Solaris (2.7.2.3), and more modern
  162.  * gcc's can probably handle assembly more like what's used in Sun's
  163.  * Native compiler version.  
  164.  *
  165.  */
  166. #elif defined (__sparc__) && defined (__GNUC__)
  167. /* Increment by 1 */
  168. inline void
  169. HXAtomicIncUINT32(UINT32* pNum)
  170. {
  171.     __asm__ __volatile__(
  172. "1:      swap    [%0], %2;               ! Swap *pNum and %2n"
  173. "        nop;                            ! delay slot...n"
  174. "        cmp     %2, %1;                 ! Is someone else using pNum?n"
  175. "        be      1b;                     ! If so, retry...n"
  176. "        nop;                            ! delay slot...yawnn"
  177. "2:      inc     %2;                     ! Increment %2n"
  178. "        cmp     %2, %1;                 ! check for overflown"
  179. "        be      2b;                     ! if so, inc againn"
  180. "        nop;                            ! but this means a delay, sighn"
  181. "        st      %2, [%0];               ! Save new value into *pNumn"
  182.         : /* no output */
  183.         : "r" (pNum), "r" (0x80000000), "r" (0x80000000)
  184.         : "cc", "memory"
  185.         );
  186. }
  187. /* Decrement by 1 */
  188. inline void
  189. HXAtomicDecUINT32(UINT32* pNum)
  190. {
  191.     __asm__ __volatile__(
  192. "1:      swap    [%0], %2;               ! Swap *pNum and %2n"
  193. "        nop;                            ! delay slot...n"
  194. "        cmp     %2, %1;                 ! Is someone else using pNum?n"
  195. "        be      1b;                     ! If so, retry...n"
  196. "        nop;                            ! delay slot...yawnn"
  197. "2:      dec     %2;                     ! Increment %2n"
  198. "        cmp     %2, %1;                 ! check for overflown"
  199. "        be      2b;                     ! if so, dec againn"
  200. "        nop;                            ! but this means a delay, sighn"
  201. "        st      %2, [%0];               ! Save new value into *pNumn"
  202.         : /* no output */
  203.         : "r" (pNum), "r" (0x80000000), "r" (0x80000000)
  204.         : "cc", "memory"
  205.         );
  206. }
  207. /* Increment by 1 and return new value */
  208. inline UINT32
  209. HXAtomicIncRetUINT32(UINT32* pNum)
  210. {
  211.     volatile UINT32 ulRet;
  212.     __asm__ __volatile__(
  213. "        mov     %2, %0;                 ! Copy %2 to %0 n"
  214. "1:      swap    [%1], %0;               ! Swap *pNum and %0n"
  215. "        nop;                            ! delay slot...n"
  216. "        cmp     %0, %2;                 ! Is someone else using pNum?n"
  217. "        be      1b;                     ! If so, retry...n"
  218. "        nop;                            ! delay slot...yawnn"
  219. "2:      inc     %0;                     ! Increment %0n"
  220. "        cmp     %0, %2;                 ! check for overflown"
  221. "        be      2b;                     ! if so, inc againn"
  222. "        nop;                            ! but this means a delay, sighn"
  223. "        st      %0, [%1];               ! Save new value into *pNumn"
  224.         : "=r" (ulRet)
  225.         : "r" (pNum), "r" (0x80000000), "0" (ulRet)
  226.         : "cc", "memory"
  227.         );
  228.     return ulRet;
  229. }
  230. /* Decrement by 1 and return new value */
  231. inline UINT32
  232. HXAtomicDecRetUINT32(UINT32* pNum)
  233. {   volatile UINT32 ulRet;
  234.     __asm__ __volatile__(
  235. "        mov     %2, %0;                 ! Copy %2 to %0 n"
  236. "1:      swap    [%1], %0;               ! Swap *pNum and %0n"
  237. "        nop;                            ! delay slot...n"
  238. "        cmp     %0, %2;                 ! Is someone else using pNum?n"
  239. "        be      1b;                     ! If so, retry...n"
  240. "        nop;                            ! delay slot...yawnn"
  241. "2:      dec     %0;                     ! Decrement %0n"
  242. "        cmp     %0, %2;                 ! check for overflown"
  243. "        be      2b;                     ! if so, dec againn"
  244. "        nop;                            ! but this means a delay, sighn"
  245. "        st      %0, [%1];               ! Save new value into *pNumn"
  246.         : "=r" (ulRet)
  247.         : "r" (pNum), "r" (0x80000000), "0" (ulRet)
  248.         : "cc", "memory"
  249.         );
  250.     return ulRet;
  251. }
  252. /* Add n */
  253. inline void
  254. HXAtomicAddUINT32(UINT32* pNum, UINT32 ulNum)
  255. {
  256.     __asm__ __volatile__(
  257. "1:      swap    [%0], %2;               ! Swap *pNum and %2n"
  258. "        nop;                            ! delay slot...n"
  259. "        cmp     %2, %1;                 ! Is someone else using pNum?n"
  260. "        be      1b;                     ! If so, retry...n"
  261. "        nop;                            ! delay slot...yawnn"
  262. "        add     %2, %3, %2;             ! Add ulNum to %2n"
  263. "        cmp     %2, %1;                 ! check for overflown"
  264. "        bne     2f;                     ! if not, skip to the endn"
  265. "        nop;                            ! but this means a delay, sighn"
  266. "        inc     %2;                     ! skip marker valuen"
  267. "2:      st      %2, [%0];               ! Save new value into *pNumn"
  268.         : /* no output */
  269.         : "r" (pNum), "r" (0x80000000), "r" (0x80000000), "r" (ulNum)
  270.         : "cc", "memory"
  271.         );
  272. }
  273. /* Subtract n */
  274. inline void
  275. HXAtomicSubUINT32(UINT32* pNum, UINT32 ulNum)
  276. {
  277.     __asm__ __volatile__(
  278. "1:      swap    [%0], %2;               ! Swap *pNum and %2n"
  279. "        nop;                            ! delay slot...n"
  280. "        cmp     %2, %1;                 ! Is someone else using pNum?n"
  281. "        be      1b;                     ! If so, retry...n"
  282. "        nop;                            ! delay slot...yawnn"
  283. "        sub     %2, %3, %2;             ! Subtract ulNum to %2n"
  284. "        cmp     %2, %1;                 ! check for overflown"
  285. "        bne     2f;                     ! if not, skip to the endn"
  286. "        nop;                            ! but this means a delay, sighn"
  287. "        inc     %2;                     ! skip marker valuen"
  288. "2:      st      %2, [%0];               ! Save new value into *pNumn"
  289.         : /* no output */
  290.         : "r" (pNum), "r" (0x80000000), "r" (0x80000000), "r" (ulNum)
  291.         : "cc", "memory"
  292.         );
  293. }
  294. /* Add n and return new value */
  295. inline UINT32
  296. HXAtomicAddRetUINT32(UINT32* pNum, UINT32 ulNum)
  297. {
  298.     volatile UINT32 ulRet; 
  299.     __asm__ __volatile__(
  300. "        mov     %2, %0                  ! Copy %2 to %0 n"
  301. "1:      swap    [%1], %0;               ! Swap *pNum and %0n"
  302. "        nop;                            ! delay slot...n"
  303. "        cmp     %0, %2;                 ! Is someone else using pNum?n"
  304. "        be      1b;                     ! If so, retry...n"
  305. "        nop;                            ! delay slot...yawnn"
  306. "        add     %0, %3, %0;             ! Add ulNum to %0n"
  307. "        cmp     %0, %2;                 ! check for overflown"
  308. "        bne     2f;                     ! if not, skip to the endn"
  309. "        nop;                            ! but this means a delay, sighn"
  310. "        inc     %0;                     ! skip marker valuen"
  311. "2:      st      %0, [%1];               ! Save new value into *pNumn"
  312.         : "=r" (ulRet)
  313.         : "r" (pNum), "r" (0x80000000), "r" (ulNum), "0" (ulRet)
  314.         : "cc", "memory"
  315.         );
  316.         return ulRet;
  317. }
  318. /* Subtract n and return new value */
  319. inline UINT32
  320. HXAtomicSubRetUINT32(UINT32* pNum, UINT32 ulNum)
  321. {   volatile UINT32 ulRet;
  322.     __asm__ __volatile__(
  323. "        mov     %2, %0                  ! Copy %2 to %0 n"
  324. "1:      swap    [%1], %0;               ! Swap *pNum and %0n"
  325. "        nop;                            ! delay slot...n"
  326. "        cmp     %0, %2;                 ! Is someone else using pNum?n"
  327. "        be      1b;                     ! If so, retry...n"
  328. "        nop;                            ! delay slot...yawnn"
  329. "        sub     %0, %3, %0;             ! Sub ulNum from %0n"
  330. "        cmp     %0, %2;                 ! check for overflown"
  331. "        bne     2f;                     ! if not, skip to the endn"
  332. "        nop;                            ! but this means a delay, sighn"
  333. "        dec     %0;                     ! skip marker valuen"
  334. "2:      st      %0, [%1];               ! Save new value into *pNumn"
  335.         : "=r" (ulRet)
  336.         : "r" (pNum), "r" (0x80000000), "r" (ulNum), "0" (ulRet)
  337.         : "cc", "memory"
  338.         );
  339.         return ulRet;
  340. }
  341. inline void HXAtomicIncINT32(INT32* p)              { HXAtomicIncUINT32((UINT32*)p); }
  342. inline void HXAtomicDecINT32(INT32* p)              { HXAtomicDecUINT32((UINT32*)p); }
  343. inline void HXAtomicAddINT32(INT32* p, INT32 n)     { HXAtomicAddUINT32((UINT32*)p, (UINT32)n); }
  344. inline void HXAtomicSubINT32(INT32* p, INT32 n)     { HXAtomicSubUINT32((UINT32*)p, (UINT32)n); }
  345. inline INT32 HXAtomicIncRetINT32(INT32* p)          { return HXAtomicIncRetUINT32((UINT32*)p); }
  346. inline INT32 HXAtomicDecRetINT32(INT32* p)          { return HXAtomicDecRetUINT32((UINT32*)p); }
  347. inline INT32 HXAtomicAddRetINT32(INT32* p, INT32 n) { return HXAtomicAddRetUINT32((UINT32*)p, (UINT32)n); }
  348. inline INT32 HXAtomicSubRetINT32(INT32* p, INT32 n) { return HXAtomicSubRetUINT32((UINT32*)p, (UINT32)n); }
  349. /***********************************************************************
  350.  * Windows / x86 (Visual C/C++)
  351.  *
  352.  * Implementation Notes:
  353.  *   'xadd' is only available in the 486 series and later, not the 386.
  354.  *   There is no 'xsub' counterpart, you have to negate the operand
  355.  *   and use 'xadd'.  Note the use of the 'lock' prefix to ensure
  356.  *   certain operations occur atomically.
  357.  */
  358. #elif defined (_M_IX86) /* && _M_IX86 > 300 XXX wschildbach: disabled until the build system delivers the correct value */
  359. /* Increment by 1 */
  360. static __inline void
  361. HXAtomicIncUINT32(UINT32* pNum)
  362. {
  363.         // register usage summary:
  364.         //   eax - pointer to the value we're modifying
  365.     _asm
  366.     {
  367.              mov  eax, pNum              ; Load the pointer into a register
  368.         lock inc  dword ptr [eax]        ; Atomically increment *pNum
  369.     }
  370. }
  371. /* Decrement by 1 */
  372. static __inline void
  373. HXAtomicDecUINT32(UINT32* pNum)
  374. {
  375.         // register usage summary:
  376.         //   eax - pointer to the value we're modifying
  377.     _asm
  378.     {
  379.              mov  eax,  pNum             ; Load the pointer into a register
  380.         lock dec  dword ptr [eax]        ; Atomically decrement *pNum
  381.     }
  382. }
  383. /* Increment by 1 and return new value */
  384. static __inline UINT32
  385. HXAtomicIncRetUINT32(UINT32* pNum)
  386. {
  387.     volatile UINT32 ulRet;     
  388.         // register usage summary:
  389.         //   eax - pointer to the value we're modifying
  390.         //   ebx - work register
  391.     _asm
  392.     {
  393.              mov  eax, pNum              ; Load the pointer into a register
  394.              mov  ebx, 0x1               ; Load increment amount into a register
  395.         lock xadd dword ptr [eax], ebx   ; Increment *pNum; ebx gets old value
  396.              inc  ebx                    ; Increment old value
  397.              mov  ulRet, ebx             ; Set the return value
  398.     }
  399.     return ulRet;
  400. }
  401. /* Decrement by 1 and return new value */
  402. static __inline UINT32
  403. HXAtomicDecRetUINT32(UINT32* pNum)
  404. {   
  405.     volatile UINT32 ulRet;
  406.         // register usage summary:
  407.         //   eax - pointer to the value we're modifying
  408.         //   ebx - work register
  409.         // note: we increment by 0xffffffff to decrement by 1
  410.     _asm
  411.     {
  412.              mov  eax, pNum              ; Load the pointer into a register
  413.              mov  ebx, 0xffffffff        ; Load decrement amount into a register
  414.         lock xadd dword ptr [eax], ebx   ; Decrement *pNum; ebx gets old value
  415.              dec  ebx                    ; decrement old value
  416.              mov  ulRet, ebx             ; Set the return value
  417.     }
  418.     return ulRet;
  419. }
  420. /* Add n */
  421. static __inline void
  422. HXAtomicAddUINT32(UINT32* pNum, UINT32 ulNum)
  423. {
  424.         // register usage summary:
  425.         //   eax - pointer to the value we're modifying
  426.         //   ebx - work register
  427.     _asm
  428.     {
  429.              mov  eax, pNum              ; Load the pointer into a register
  430.              mov  ebx, ulNum             ; Load increment amount into a register
  431.         lock add  dword ptr [eax], ebx   ; Increment *pNum by ulNum
  432.     }
  433. }
  434. /* Subtract n */
  435. static __inline void
  436. HXAtomicSubUINT32(UINT32* pNum, UINT32 ulNum)
  437. {
  438.         // register usage summary:
  439.         //   eax - pointer to the value we're modifying
  440.         //   ebx - work register
  441.     _asm
  442.     {
  443.              mov  eax, pNum              ; Load the pointer into a register
  444.              mov  ebx, ulNum             ; Load increment amount into a register
  445.         lock sub  dword ptr [eax], ebx   ; Atomically decrement *pNum by ulNum
  446.     }
  447. }
  448. /* Add n and return new value */
  449. static __inline UINT32
  450. HXAtomicAddRetUINT32(UINT32* pNum, UINT32 ulNum)
  451. {
  452.     volatile UINT32 ulRet;
  453.         // register usage summary:
  454.         //   eax - pointer to the value we're modifying
  455.         //   ebx - work register
  456.         //   ecx - work register #2
  457.     _asm
  458.     {
  459.              mov  eax, pNum              ; Load the pointer into a register
  460.              mov  ebx, ulNum             ; Load increment amount into a register
  461.              mov  ecx, ebx               ; copy ebx into ecx
  462.         lock xadd dword ptr [eax], ecx   ; Increment *pNum; ecx gets old value
  463.              add  ecx, ebx               ; Add ulNum to it
  464.              mov  ulRet, ecx             ; save result in ulRet
  465.     }
  466.     return ulRet;
  467. }
  468. /* Subtract n and return new value */
  469. static __inline UINT32
  470. HXAtomicSubRetUINT32(UINT32* pNum, UINT32 ulNum) 
  471. {   
  472.     volatile UINT32 ulRet;
  473.         // register usage summary:
  474.         //   eax - pointer to the value we're modifying
  475.         //   ebx - work register
  476.         //   ecx - work register #2
  477.     _asm
  478.     {
  479.              mov  eax, pNum              ; Load the pointer into a register
  480.              mov  ebx, ulNum             ; Load increment amount into a register
  481.              mov  ecx, 0x0               ; zero out ecx
  482.              sub  ecx, ebx               ; compute -(ulNum), saving in ecx
  483.         lock xadd dword ptr [eax], ecx   ; Decrement *pNum; ecx gets old value
  484.              sub  ecx, ebx               ; subtract ulNum from it
  485.              mov  ulRet, ecx             ; save result in ulRet
  486.     }
  487.     return ulRet;
  488. }
  489. static __inline void HXAtomicIncINT32(INT32* p)              { HXAtomicIncUINT32((UINT32*)p); }
  490. static __inline void HXAtomicDecINT32(INT32* p)              { HXAtomicDecUINT32((UINT32*)p); }
  491. static __inline void HXAtomicAddINT32(INT32* p, INT32 n)     { HXAtomicAddUINT32((UINT32*)p, (UINT32)n); }
  492. static __inline void HXAtomicSubINT32(INT32* p, INT32 n)     { HXAtomicSubUINT32((UINT32*)p, (UINT32)n); }
  493. static __inline INT32 HXAtomicIncRetINT32(INT32* p)          { return HXAtomicIncRetUINT32((UINT32*)p); }
  494. static __inline INT32 HXAtomicDecRetINT32(INT32* p)          { return HXAtomicDecRetUINT32((UINT32*)p); }
  495. static __inline INT32 HXAtomicAddRetINT32(INT32* p, INT32 n) { return HXAtomicAddRetUINT32((UINT32*)p, (UINT32)n); }
  496. static __inline INT32 HXAtomicSubRetINT32(INT32* p, INT32 n) { return HXAtomicSubRetUINT32((UINT32*)p, (UINT32)n); }
  497. /***********************************************************************
  498.  * Intel x86 (gcc) / Unix  -- i486 and higher
  499.  *
  500.  * Implementation Notes:
  501.  *   'xadd' is only available in the 486 series and later, not the 386.
  502.  *   There is no 'xsub' counterpart, you have to negate the operand
  503.  *   and use 'xadd'.  Note the use of the 'lock' prefix to ensure
  504.  *   certain operations occur atomically.
  505.  *
  506.  *   OpenBSD is excluded since the standard assembler on x86 systems
  507.  *   can't handle the xadd instruction.
  508.  *
  509.  */
  510. #elif defined(__GNUC__) && !defined(_OPENBSD) && 
  511.       (__GNUC__>2 || (__GNUC__==2 && __GNUC_MINOR__>=95)) && 
  512.       ( defined (__i486__) || defined (__i586__) || defined (__i686__) || 
  513.         defined (__pentium__) || defined (__pentiumpro__))
  514. /* Increment by 1 */
  515. static __inline__ void
  516. HXAtomicIncUINT32(UINT32* pNum)
  517. {
  518.     __asm__ __volatile__(
  519.         "lock incl (%0);"                // atomically add 1 to *pNum
  520.         : /* no output */
  521.         : "r" (pNum)
  522.         : "cc", "memory"
  523.         );
  524. }
  525. /* Decrement by 1 */
  526. static __inline__ void
  527. HXAtomicDecUINT32(UINT32* pNum)
  528. {
  529.     __asm__ __volatile__(
  530.         "lock decl (%0);"                // atomically add -1 to *pNum
  531.         : /* no output */
  532.         : "r" (pNum)
  533.         : "cc", "memory"
  534.         );
  535. }
  536. /* Increment by 1 and return new value */
  537. static __inline__ UINT32
  538. HXAtomicIncRetUINT32(UINT32* pNum)
  539. {
  540.     volatile UINT32 ulRet;
  541.     __asm__ __volatile__(
  542.         "lock xaddl %0, (%1);"           // atomically add 1 to *pNum
  543.         "     inc   %0;"                 // old value in %0, increment it
  544.         : "=r" (ulRet)
  545.         : "r" (pNum), "0" (0x1)
  546.         : "cc", "memory"
  547.         );
  548.     return ulRet;
  549. }
  550. /* Decrement by 1 and return new value */
  551. static __inline__ UINT32
  552. HXAtomicDecRetUINT32(UINT32* pNum)
  553. {   
  554.     volatile UINT32 ulRet;
  555.     __asm__ __volatile__(
  556.         "lock xaddl %0, (%1);"           // atomically add -1 to *pNum
  557.         "     dec   %0;"                 // old value in %0, decrement it
  558.         : "=r" (ulRet)
  559.         : "r" (pNum), "0" (-1)
  560.         : "cc", "memory"
  561.         );
  562.     return ulRet;
  563. }
  564. /* Add n */
  565. static __inline__ void
  566. HXAtomicAddUINT32(UINT32* pNum, UINT32 ulNum)
  567. {
  568.     __asm__ __volatile__(
  569.         "lock addl %1, (%0);"            // atomically add ulNum to *pNum
  570.         : /* no output */
  571.         : "r" (pNum), "r" (ulNum)
  572.         : "cc", "memory"
  573.         );
  574. }
  575. /* Subtract n */
  576. static __inline__ void
  577. HXAtomicSubUINT32(UINT32* pNum, UINT32 ulNum)
  578. {
  579.     __asm__ __volatile__(
  580.         "lock subl %1, (%0);"            // atomically add ulNum to *pNum
  581.         : /* no output */
  582.         : "r" (pNum), "r" (ulNum)
  583.         : "cc", "memory"
  584.         );
  585. }
  586. /* Add n and return new value */
  587. static __inline__ UINT32
  588. HXAtomicAddRetUINT32(UINT32* pNum, UINT32 ulNum)
  589. {
  590.     volatile UINT32 ulRet;
  591.     __asm__ __volatile__(
  592.         "     mov   %2, %0;"             // copy ulNum into %0
  593.         "lock xaddl %0, (%1);"           // atomically add ulNum to *pNum
  594.         "     add   %2, %0;"             // old value in %0, add ulNum
  595.         : "=r" (ulRet)
  596.         : "r" (pNum), "r" (ulNum), "0" (0)
  597.         : "cc", "memory"
  598.         );
  599.     return ulRet;
  600. }
  601. /* Subtract n and return new value */
  602. static __inline__ UINT32
  603. HXAtomicSubRetUINT32(UINT32* pNum, UINT32 ulNum) 
  604. {   
  605.     volatile UINT32 ulRet;
  606.     __asm__ __volatile__(
  607.         "     sub   %2, %0;"             // negate ulNum, saving in %0
  608.         "lock xaddl %0, (%1);"           // atomically add -(ulNum) to *pNum
  609.         "     sub   %2, %0;"             // old value in %0, subtract ulNum
  610.         : "=r" (ulRet)
  611.         : "r" (pNum), "r" (ulNum), "0" (0)
  612.         : "cc", "memory"
  613.         );
  614.     return ulRet;
  615. }
  616. static __inline__ void HXAtomicIncINT32(INT32* p)              { HXAtomicIncUINT32((UINT32*)p); }
  617. static __inline__ void HXAtomicDecINT32(INT32* p)              { HXAtomicDecUINT32((UINT32*)p); }
  618. static __inline__ void HXAtomicAddINT32(INT32* p, INT32 n)     { HXAtomicAddUINT32((UINT32*)p, (UINT32)n); }
  619. static __inline__ void HXAtomicSubINT32(INT32* p, INT32 n)     { HXAtomicSubUINT32((UINT32*)p, (UINT32)n); }
  620. static __inline__ INT32 HXAtomicIncRetINT32(INT32* p)          { return HXAtomicIncRetUINT32((UINT32*)p); }
  621. static __inline__ INT32 HXAtomicDecRetINT32(INT32* p)          { return HXAtomicDecRetUINT32((UINT32*)p); }
  622. static __inline__ INT32 HXAtomicAddRetINT32(INT32* p, INT32 n) { return HXAtomicAddRetUINT32((UINT32*)p, (UINT32)n); }
  623. static __inline__ INT32 HXAtomicSubRetINT32(INT32* p, INT32 n) { return HXAtomicSubRetUINT32((UINT32*)p, (UINT32)n); }
  624. /***********************************************************************
  625.  * HP-UX / IA64 (Native compiler)
  626.  *
  627.  * Implementation Notes:
  628.  *      A work-in-progress...
  629.  */
  630. #elif defined(_HPUX) && defined(_IA64)
  631. #if defined(__cplusplus)
  632. extern "C" {
  633. #endif
  634.     UINT32 _HXAtomicIncRetUINT32 (UINT32* pNum);
  635.     UINT32 _HXAtomicDecRetUINT32 (UINT32* pNum);
  636.     UINT32 _HXAtomicAddRetUINT32 (UINT32* pNum, UINT32 ulNum);
  637.     UINT32 _HXAtomicSubRetUINT32 (UINT32* pNum, UINT32 ulNum);
  638. #if defined(__cplusplus)
  639. }
  640. #endif
  641. #define HXAtomicIncINT32(p)       _HXAtomicIncRetUINT32((UINT32*)(p))
  642. #define HXAtomicDecINT32(p)       _HXAtomicDecRetUINT32((UINT32*)(p))
  643. #define HXAtomicIncRetINT32(p)    _HXAtomicIncRetUINT32((UINT32*)(p))
  644. #define HXAtomicDecRetINT32(p)    _HXAtomicDecRetUINT32((UINT32*)(p))
  645. #define HXAtomicAddINT32(p,n)     _HXAtomicAddRetUINT32((UINT32*)(p),(INT32)(n))
  646. #define HXAtomicSubINT32(p,n)     _HXAtomicSubRetUINT32((UINT32*)(p),(INT32)(n))
  647. #define HXAtomicAddRetINT32(p,n)  _HXAtomicAddRetUINT32((UINT32*)(p),(INT32)(n))
  648. #define HXAtomicSubRetINT32(p,n)  _HXAtomicSubRetUINT32((UINT32*)(p),(INT32)(n))
  649. #define HXAtomicIncUINT32(p)      _HXAtomicIncRetUINT32((p))
  650. #define HXAtomicDecUINT32(p)      _HXAtomicDecRetUINT32((p))
  651. #define HXAtomicIncRetUINT32(p)   _HXAtomicIncRetUINT32((p))
  652. #define HXAtomicDecRetUINT32(p)   _HXAtomicDecRetUINT32((p))
  653. #define HXAtomicAddUINT32(p,n)    _HXAtomicAddRetUINT32((p),(n))
  654. #define HXAtomicSubUINT32(p,n)    _HXAtomicSubRetUINT32((p),(n))
  655. #define HXAtomicAddRetUINT32(p,n) _HXAtomicAddRetUINT32((p),(n))
  656. #define HXAtomicSubRetUINT32(p,n) _HXAtomicSubRetUINT32((p),(n))
  657. /***********************************************************************
  658.  * Tru64 (OSF1) / Alpha (Native compiler)
  659.  *
  660.  * Implementation Notes:
  661.  *
  662.  * The Alpha CPU provides instructions to load-lock a value,
  663.  * modify it, and attempt to write it back.  If the value has
  664.  * been modified by someone else since the load-lock occured,
  665.  * the write will fail and you can check the status code to
  666.  * know whether you need to retry or not.
  667.  *
  668.  */
  669. #elif defined (__alpha)
  670. #include <c_asm.h>
  671. /* Increment by 1 and return new value */
  672. inline INT32
  673. HXAtomicIncRetINT32(INT32* pNum)
  674. {
  675.     return asm (
  676.         "10:     ldl_l   %t0, (%a0);"       // Load-lock value into a register
  677.         "        addl    %t0, 1, %t0;"      // Increment value
  678.         "        or      %t0, %zero, %v0;"  // set new value for return.
  679.         "        stl_c   %t0, (%a0);"       // Save new value into *pNum
  680.         "        beq     %t0, 10b;"         // Retry if sequence failed
  681.         , pNum);
  682. }
  683. /* Decrement by 1 and return new value */
  684. inline INT32
  685. HXAtomicDecRetINT32(INT32* pNum)
  686. {
  687.     return asm (
  688.         "10:     ldl_l   %t0, (%a0);"       // Load-lock value into a register
  689.         "        subl    %t0, 1, %t0;"      // Decrement value
  690.         "        or      %t0, %zero, %v0;"  // set new value for return.
  691.         "        stl_c   %t0, (%a0);"       // Save new value into *pNum
  692.         "        beq     %t0, 10b;"         // Retry if sequence failed
  693.         , pNum);
  694. }
  695. /* Add n and return new value */
  696. inline INT32
  697. HXAtomicAddRetINT32(INT32* pNum, INT32 n)
  698. {
  699.     return asm (
  700.         "10:     ldl_l   %t0, (%a0);"       // Load-lock value into a register
  701.         "        addl    %t0, %a1, %t0;"    // Add n to value
  702.         "        or      %t0, %zero, %v0;"  // set new value for return.
  703.         "        stl_c   %t0, (%a0);"       // Save new value into *pNum
  704.         "        beq     %t0, 10b;"         // Retry if sequence failed
  705.         , pNum, n);
  706. }
  707. /* Subtract n and return new value */
  708. inline INT32
  709. HXAtomicSubRetINT32(INT32* pNum, INT32 n)
  710. {
  711.     return asm (
  712.         "10:     ldl_l   %t0, (%a0);"       // Load-lock value into a register
  713.         "        subl    %t0, %a1, %t0;"    // Subtract n from value
  714.         "        or      %t0, %zero, %v0;"  // set new value for return.
  715.         "        stl_c   %t0, (%a0);"       // Save new value into *pNum
  716.         "        beq     %t0, 10b;"         // Retry if sequence failed
  717.         , pNum, n);
  718. }
  719. /* Increment by 1 and return new value */
  720. inline UINT32
  721. HXAtomicIncRetUINT32(UINT32* pNum)
  722. {
  723.     return asm (
  724.         "10:     ldl_l   %t0, (%a0);"       // Load-lock value into a register
  725.         "        addl    %t0, 1, %t0;"      // Increment value
  726.         "        or      %t0, %zero, %v0;"  // set new value for return.
  727.         "        stl_c   %t0, (%a0);"       // Save new value into *pNum
  728.         "        beq     %t0, 10b;"         // Retry if sequence failed
  729.         , pNum);
  730. }
  731. /* Decrement by 1 and return new value */
  732. inline UINT32
  733. HXAtomicDecRetUINT32(UINT32* pNum)
  734. {
  735.     return asm (
  736.         "10:     ldl_l   %t0, (%a0);"       // Load-lock value into a register
  737.         "        subl    %t0, 1, %t0;"      // Decrement value
  738.         "        or      %t0, %zero, %v0;"  // set new value for return.
  739.         "        stl_c   %t0, (%a0);"       // Save new value into *pNum
  740.         "        beq     %t0, 10b;"         // Retry if sequence failed
  741.         , pNum);
  742. }
  743. /* Add n and return new value */
  744. inline UINT32
  745. HXAtomicAddRetUINT32(UINT32* pNum, UINT32 n)
  746. {
  747.     return asm (
  748.         "10:     ldl_l   %t0, (%a0);"       // Load-lock value into a register
  749.         "        addl    %t0, %a1, %t0;"    // Add n to value
  750.         "        or      %t0, %zero, %v0;"  // set new value for return.
  751.         "        stl_c   %t0, (%a0);"       // Save new value into *pNum
  752.         "        beq     %t0, 10b;"         // Retry if sequence failed
  753.         , pNum, n);
  754. }
  755. /* Subtract n and return new value */
  756. inline UINT32
  757. HXAtomicSubRetUINT32(UINT32* pNum, UINT32 n)
  758. {
  759.     return asm (
  760.         "10:     ldl_l   %t0, (%a0);"       // Load-lock value into a register
  761.         "        subl    %t0, %a1, %t0;"    // Subtract n from value
  762.         "        or      %t0, %zero, %v0;"  // set new value for return.
  763.         "        stl_c   %t0, (%a0);"       // Save new value into *pNum
  764.         "        beq     %t0, 10b;"         // Retry if sequence failed
  765.         , pNum, n);
  766. }
  767. #define HXAtomicIncINT32(p)    HXAtomicIncRetINT32((p))
  768. #define HXAtomicDecINT32(p)    HXAtomicDecRetINT32((p))
  769. #define HXAtomicAddINT32(p,n)  HXAtomicAddRetINT32((p),(n))
  770. #define HXAtomicSubINT32(p,n)  HXAtomicSubRetINT32((p),(n))
  771. #define HXAtomicIncUINT32(p)   HXAtomicIncRetUINT32((p))
  772. #define HXAtomicDecUINT32(p)   HXAtomicDecRetUINT32((p))
  773. #define HXAtomicAddUINT32(p,n) HXAtomicAddRetUINT32((p),(n))
  774. #define HXAtomicSubUINT32(p,n) HXAtomicSubRetUINT32((p),(n))
  775. /***********************************************************************
  776.  * AIX / PowerPC (Native compiler)
  777.  *
  778.  * Implementation Notes:
  779.  *
  780.  * XXXDC: The xlc compiler is able to do inline asm for C but when I do
  781.  * it for C++ it crashes, so for now I have resorted to putting
  782.  * the asm in a seperate assembler routine.  The way you inline with
  783.  * xlc/xlC is difficult to use, requiring the use of "#pragma mc_func".
  784.  */
  785. #elif defined (_AIX)
  786. //defined in common/util/platform/aix/atomicops.s
  787. #if defined(__cplusplus)
  788. extern "C" {
  789. #endif
  790.     INT32 _HXAtomicAddRetINT32   (INT32*  pNum, INT32  lNum);
  791.     INT32 _HXAtomicSubRetINT32   (INT32*  pNum, INT32  lNum);
  792.     UINT32 _HXAtomicAddRetUINT32 (UINT32* pNum, UINT32 ulNum);
  793.     UINT32 _HXAtomicSubRetUINT32 (UINT32* pNum, UINT32 ulNum);
  794. #if defined(__cplusplus)
  795. }
  796. #endif
  797. #define HXAtomicIncINT32(p)       _HXAtomicAddRetINT32((p),(INT32)1)
  798. #define HXAtomicDecINT32(p)       _HXAtomicSubRetINT32((p),(INT32)1)
  799. #define HXAtomicIncRetINT32(p)    _HXAtomicAddRetINT32((p),(INT32)1)
  800. #define HXAtomicDecRetINT32(p)    _HXAtomicSubRetINT32((p),(INT32)1)
  801. #define HXAtomicAddINT32(p,n)     _HXAtomicAddRetINT32((p),(n))
  802. #define HXAtomicSubINT32(p,n)     _HXAtomicSubRetINT32((p),(n))
  803. #define HXAtomicAddRetINT32(p,n)  _HXAtomicAddRetINT32((p),(n))
  804. #define HXAtomicSubRetINT32(p,n)  _HXAtomicSubRetINT32((p),(n))
  805. #define HXAtomicIncUINT32(p)      _HXAtomicAddRetUINT32((p),(UINT32)1)
  806. #define HXAtomicDecUINT32(p)      _HXAtomicSubRetUINT32((p),(UINT32)1)
  807. #define HXAtomicIncRetUINT32(p)   _HXAtomicAddRetUINT32((p),(UINT32)1)
  808. #define HXAtomicDecRetUINT32(p)   _HXAtomicSubRetUINT32((p),(UINT32)1)
  809. #define HXAtomicAddUINT32(p,n)    _HXAtomicAddRetUINT32((p),(n))
  810. #define HXAtomicSubUINT32(p,n)    _HXAtomicSubRetUINT32((p),(n))
  811. #define HXAtomicAddRetUINT32(p,n) _HXAtomicAddRetUINT32((p),(n))
  812. #define HXAtomicSubRetUINT32(p,n) _HXAtomicSubRetUINT32((p),(n))
  813. /***********************************************************************
  814.  * MAC / PowerPC (CW)
  815.  *
  816.  * Implementation Notes:
  817.  *
  818.  * This will need to be rewritten, probably, once we move away from CW to PB.
  819.  *
  820.  * Note: This is an imcompletely-defined platform, be aware that
  821.  * not all standard HXAtomic operators are defined!
  822.  *
  823.  */
  824. #elif defined(_MACINTOSH) && defined(__MWERKS__)
  825. inline UINT32
  826. HXAtomicIncRetUINT32(register UINT32* pNum)
  827. {
  828.     register UINT32 zeroOffset = 0;
  829.     register UINT32 temp;
  830.     asm
  831.     {
  832. again:
  833.     lwarx temp, zeroOffset, pNum
  834.     addi temp, temp, 1
  835.     stwcx. temp, zeroOffset, pNum
  836.     bne- again
  837.     }
  838.     return temp;
  839. }
  840. inline UINT32
  841. HXAtomicDecRetUINT32(register UINT32* pNum)
  842. {
  843.     register UINT32 zeroOffset = 0;
  844.     register UINT32 temp;
  845.     asm
  846.     {
  847. again:
  848.     lwarx temp, zeroOffset, pNum
  849.     subi temp, temp, 1
  850.     stwcx. temp, zeroOffset, pNum
  851.     bne- again
  852.     }
  853.     return temp;
  854. }
  855. /***********************************************************************
  856.  * MAC / PowerPC (PB)
  857.  *
  858.  * Implementation Notes:
  859.  *
  860.  * Use the atomic operations exposed by DriverSynchronization.h
  861.  *
  862.  * Note: This is an imcompletely-defined platform, be aware that
  863.  * not all standard HXAtomic operators are defined!
  864.  *
  865.  */
  866. #elif defined(_MACINTOSH) || defined(_MAC_UNIX)
  867. inline UINT32
  868. HXAtomicIncRetUINT32(UINT32* pNum)
  869. {
  870.     return (UINT32)(IncrementAtomic((SInt32*)pNum) + 1);
  871. }
  872. inline UINT32
  873. HXAtomicDecRetUINT32(UINT32* pNum)
  874. {
  875.     return (UINT32)(DecrementAtomic((SInt32*)pNum) - 1);
  876. }
  877. /***********************************************************************
  878.  * Linux / PowerPC
  879.  *
  880.  * Implementation Notes:
  881.  *
  882.  * Use PowerPC load exclusive and store exclusive instructions
  883.  *
  884.  */
  885. #elif defined(_LINUX) && defined(__powerpc__)
  886. static inline UINT32
  887. HXAtomicIncRetUINT32(UINT32* pNum)
  888. {
  889.     volatile UINT32 result;
  890. __asm__ __volatile__ (
  891. "1:      lwarx  %0, %3, %2;n"
  892. "        addi   %0, %0, 1;n"
  893. "        stwcx. %0, %3, %2;n"
  894. "        bne- 1b;"
  895.          : "=b" (result)
  896.          : "0" (result), "b" (pNum), "b" (0x0)
  897.          : "cc", "memory"
  898.  );
  899. return result;
  900. }
  901. static inline UINT32
  902. HXAtomicDecRetUINT32(UINT32* pNum)
  903. {
  904.     volatile UINT32 result;
  905. __asm__ __volatile__ (
  906. "1:      lwarx  %0, %3, %2;n"
  907. "        subi   %0, %0, 1;n"
  908. "        stwcx. %0, %3, %2;n"
  909. "        bne- 1b;"
  910.          : "=b" (result)
  911.          : "0" (result), "b" (pNum), "b" (0x0)
  912.          : "cc", "memory"
  913.          );
  914. return result;
  915. }
  916. /***********************************************************************
  917.  * Generic
  918.  *
  919.  * Implementation Notes:
  920.  *
  921.  * This should work on any platform with a HXMutex-style mutex.
  922.  * It allocates a pool of mutexes and hashes the int pointers
  923.  * to one of the mutexes.  Since the mutexes are held for
  924.  * such a short time, only long enough to increment an int,
  925.  * collisions should be extremely rare and this should work fine,
  926.  * although it is probably less fast than the extra-high-performance
  927.  * atomic operators provided above.  You need to link in atomic.cpp
  928.  * to get HXAtomic::m_pLocks defined.
  929.  *
  930.  * Basic design of the mutex-based lock-pool implementation:
  931.  *   At startup, allocate an array of N mutexes (where N is a power of 2).
  932.  *   When a method is called, hash the int pointer to one of the locks.
  933.  *   Lock this mutex.
  934.  *   Modify the value.
  935.  *   Unlock this mutex.
  936.  *
  937.  *
  938.  * Platform-specific notes:
  939.  *   Any platforms that use this should be documented here!
  940.  *   Why are you using the generic operators for this platform?
  941.  *
  942.  * HP-UX / HP-PA:
  943.  *   This is used on the HP-PA processor since it doesn't provide the
  944.  *   necessary assembler operators to implement proper atomic updates
  945.  *   of ints.  HP's mutex primitive seems pretty fast however, resulting
  946.  *   in a workable solution.
  947.  *
  948.  * OpenBSD:
  949.  *   The standard assembler on x86 can't handle the gcc/asm operators
  950.  *   defined above, so we're using the lock-pool approach for now.
  951.  *   This approach also makes it possible to support non-x86 OpenBSD
  952.  *   builds more easily (someday).
  953.  *
  954.  */
  955. #elif defined(_HPUX) || defined(_OPENBSD)
  956. #include "microsleep.h"
  957. #include "hxcom.h"
  958. #include "hxmutexlock.h"
  959. class HXAtomic
  960. {
  961. public:
  962.     HXAtomic();
  963.     ~HXAtomic();
  964.     void InitLockPool();
  965.     /* Users of the HXAtomic routines should *NEVER* call these directly.
  966.      * They should *ALWAYS* use the HXAtomicAddRetINT32-style macros instead.
  967.      */
  968.     INT32  _AddRetINT32  (INT32*  pNum, INT32  nNum);
  969.     UINT32 _AddRetUINT32 (UINT32* pNum, UINT32 ulNum);
  970.     INT32  _SubRetINT32  (INT32*  pNum, INT32  nNum);
  971.     UINT32 _SubRetUINT32 (UINT32* pNum, UINT32 ulNum);
  972. private:
  973.     void Lock   (HX_MUTEX pLock);
  974.     void Unlock (HX_MUTEX pLock);
  975.     HX_MUTEX* m_pLocks;
  976. };
  977. extern HXAtomic g_AtomicOps; //in common/util/atomicops.cpp
  978. #define HXAtomicIncINT32(p)       g_AtomicOps._AddRetINT32((p),(INT32)1)
  979. #define HXAtomicDecINT32(p)       g_AtomicOps._SubRetINT32((p),(INT32)1)
  980. #define HXAtomicIncRetINT32(p)    g_AtomicOps._AddRetINT32((p),(INT32)1)
  981. #define HXAtomicDecRetINT32(p)    g_AtomicOps._SubRetINT32((p),(INT32)1)
  982. #define HXAtomicAddRetINT32(p,n)  g_AtomicOps._AddRetINT32((p),(n))
  983. #define HXAtomicSubRetINT32(p,n)  g_AtomicOps._SubRetINT32((p),(n))
  984. #define HXAtomicAddINT32(p,n)     g_AtomicOps._AddRetINT32((p),(n))
  985. #define HXAtomicSubINT32(p,n)     g_AtomicOps._SubRetINT32((p),(n))
  986. #define HXAtomicIncUINT32(p)      g_AtomicOps._AddRetUINT32((p),(UINT32)1)
  987. #define HXAtomicDecUINT32(p)      g_AtomicOps._SubRetUINT32((p),(UINT32)1)
  988. #define HXAtomicIncRetUINT32(p)   g_AtomicOps._AddRetUINT32((p),(UINT32)1)
  989. #define HXAtomicDecRetUINT32(p)   g_AtomicOps._SubRetUINT32((p),(UINT32)1)
  990. #define HXAtomicAddRetUINT32(p,n) g_AtomicOps._AddRetUINT32((p),(n))
  991. #define HXAtomicSubRetUINT32(p,n) g_AtomicOps._SubRetUINT32((p),(n))
  992. #define HXAtomicAddUINT32(p,n)    g_AtomicOps._AddRetUINT32((p),(n))
  993. #define HXAtomicSubUINT32(p,n)    g_AtomicOps._SubRetUINT32((p),(n))
  994. /***********************************************************************
  995.  * SYMBIAN
  996.  *
  997.  * Implementation Notes:
  998.  *
  999.  * Note: This is an imcompletely-defined platform, be aware that
  1000.  * not all standard HXAtomic operators are defined!
  1001.  *
  1002.  */
  1003. #elif defined(_SYMBIAN)
  1004. /* Increment by 1 and return new value */
  1005. inline INT32
  1006. HXAtomicIncRetINT32(INT32* pNum)
  1007. {
  1008.     return User::LockedInc(*((TInt*)pNum)) + 1;
  1009. }
  1010. /* Decrement by 1 and return new value */
  1011. inline INT32
  1012. HXAtomicDecRetINT32(INT32* pNum)
  1013. {
  1014.     return User::LockedDec(*((TInt*)pNum)) - 1;
  1015. }
  1016. /* Increment by 1 and return new value */
  1017. inline UINT32
  1018. HXAtomicIncRetUINT32(UINT32* pNum)
  1019. {
  1020.     return ((UINT32)User::LockedInc(*((TInt*)pNum))) + 1;
  1021. }
  1022. /* Decrement by 1 and return new value */
  1023. inline UINT32
  1024. HXAtomicDecRetUINT32(UINT32* pNum)
  1025. {
  1026.     return ((UINT32)User::LockedDec(*((TInt*)pNum))) - 1;
  1027. }
  1028. #define HXAtomicIncINT32(p)    HXAtomicIncRetINT32((p))
  1029. #define HXAtomicDecINT32(p)    HXAtomicDecRetINT32((p))
  1030. #define HXAtomicIncUINT32(p)   HXAtomicIncRetUINT32((p))
  1031. #define HXAtomicDecUINT32(p)   HXAtomicDecRetUINT32((p))
  1032. #if 0
  1033. /* 
  1034.  * Add and subtract operations are not implemented
  1035.  * at this time because there isn't an easy way to
  1036.  * do it using the facilities provided by Symbian.
  1037.  * Assembly will likely be needed.
  1038.  */
  1039. /* Add n and return new value */
  1040. inline INT32
  1041. HXAtomicAddRetINT32(INT32* pNum, INT32 n)
  1042. {
  1043. }
  1044. /* Subtract n and return new value */
  1045. inline INT32
  1046. HXAtomicSubRetINT32(INT32* pNum, INT32 n)
  1047. {
  1048. }
  1049. /* Add n and return new value */
  1050. inline UINT32
  1051. HXAtomicAddRetUINT32(UINT32* pNum, UINT32 n)
  1052. {
  1053. }
  1054. /* Subtract n and return new value */
  1055. inline UINT32
  1056. HXAtomicSubRetUINT32(UINT32* pNum, UINT32 n)
  1057. {
  1058. }
  1059. #define HXAtomicAddINT32(p,n)  HXAtomicAddRetINT32((p),(n))
  1060. #define HXAtomicSubINT32(p,n)  HXAtomicSubRetINT32((p),(n))
  1061. #define HXAtomicAddUINT32(p,n) HXAtomicAddRetUINT32((p),(n))
  1062. #define HXAtomicSubUINT32(p,n) HXAtomicSubRetUINT32((p),(n))
  1063. #endif
  1064. /***********************************************************************
  1065.  * Linux / ARM (gcc)
  1066.  *
  1067.  * Implementation Notes:
  1068.  *
  1069.  * This implementation sacrifices being able to store the value
  1070.  * 0x800000000 in the INT32 value, which is a special "busy" marker value.
  1071.  * Since these are intended for use primarily with AddRef/Release and
  1072.  * resource usage counters, this should be acceptable for now.  If a counter
  1073.  * is incremented to the point it would conflict with the flag, it is
  1074.  * incremented one more to hop over it.  The same in reverse for decrement.
  1075.  *
  1076.  * Basic design of the flag-based implementation:
  1077.  *   1. Load a register with 0x80000000
  1078.  *   2. _atomically_ swap it with the INT32 (critical!)
  1079.  *   3. Compare what we got with 0x80000000
  1080.  *   4. Branch if equal to #2
  1081.  *   5. Increment (or decrement) the result
  1082.  *   6. Compare to 0x80000000
  1083.  *   7. Increment (or decrement) again if equal
  1084.  *   8. Save the new value to the INT32's location in memory
  1085.  *   9. Return new INT32 result if required
  1086.  *   
  1087.  */
  1088. #elif defined (_ARM) && defined (__GNUC__)
  1089. /* Increment by 1 */
  1090. inline void
  1091. HXAtomicIncUINT32(UINT32* pNum)
  1092. {
  1093.     UINT32 ulTmp;
  1094.     __asm__ __volatile__(
  1095. "        mov   %0, #0x80000000;n"      /* Set ulTmp to 0x800000000    */
  1096. "1:      swp   %0, %0, [%1];n"         /* Swap *pNum and ulTmp        */
  1097. "        cmp   %0, #0x80000000;n"      /* Is someone else using pNum? */
  1098. "        beq   1;n"                    /* If so, retry...             */
  1099. "        add   %0, %0, #1;n"           /* Increment ulTmp             */
  1100. "        cmp   %0, #0x80000000;n"      /* check for overflow          */
  1101. "        addeq %0, %0, #1;n"           /* if so, increment again      */
  1102. "        str   %0, [%1];n"             /* Save new value into *pNum   */
  1103.         : /* no output */
  1104.         : "r" (ulTmp), "r" (pNum)
  1105.         : "cc", "memory"
  1106.         );
  1107. }
  1108. /* Decrement by 1 */
  1109. inline void
  1110. HXAtomicDecUINT32(UINT32* pNum)
  1111. {
  1112.     UINT32 ulTmp;
  1113.     __asm__ __volatile__(
  1114. "        mov   %0, #0x80000000;n"      /* Set ulTmp to 0x800000000    */
  1115. "1:      swp   %0, %0, [%1];n"         /* Swap *pNum and ulTmp        */
  1116. "        cmp   %0, #0x80000000;n"      /* Is someone else using pNum? */
  1117. "        beq   1;n"                    /* If so, retry...             */
  1118. "        sub   %0, %0, #1;n"           /* Decrement ulTmp             */
  1119. "        cmp   %0, #0x80000000;n"      /* check for overflow          */
  1120. "        subeq %0, %0, #1;n"           /* if so, decrement again      */
  1121. "        str   %0, [%1];n"             /* Save new value into *pNum   */
  1122.         : /* no output */
  1123.         :  "r" (ulTmp), "r" (pNum)
  1124.         : "cc", "memory"
  1125.         );
  1126. }
  1127. /* Increment by 1 and return new value */
  1128. inline UINT32
  1129. HXAtomicIncRetUINT32(UINT32* pNum)
  1130. {
  1131.     volatile UINT32 ulRet;
  1132.     __asm__ __volatile__(
  1133. "        mov   %0, #0x80000000;n"      /* Set ulRet to 0x80000000     */
  1134. "1:      swp   %0, %0, [%1];n"         /* Swap *pNum and ulRet        */
  1135. "        cmp   %0, #0x80000000;n"      /* Is someone else using pNum? */
  1136. "        beq   1;n"                    /* If so, retry...             */
  1137. "        add   %0, %0, #1;n"           /* Increment ulRet             */
  1138. "        cmp   %0, #0x80000000;n"      /* check for overflow          */
  1139. "        addeq %0, %0, #1;n"         /* if so, increment again      */
  1140. "        str   %0, [%1];n"             /* Save new value into *pNum   */
  1141.         : "=&r" (ulRet)
  1142.         : "r" (pNum)
  1143.         : "cc", "memory"
  1144.         );
  1145.     return ulRet;
  1146. }
  1147. /* Decrement by 1 and return new value */
  1148. inline UINT32
  1149. HXAtomicDecRetUINT32(UINT32* pNum)
  1150. {
  1151.     volatile UINT32 ulRet;
  1152.     __asm__ __volatile__(
  1153. "        mov   %0, #0x80000000;n"      /* Set ulRet to 0x80000000     */
  1154. "1:      swp   %0, %0, [%1];n"         /* Swap *pNum and ulRet        */
  1155. "        cmp   %0, #0x80000000;n"      /* Is someone else using pNum? */
  1156. "        beq   1;n"                    /* If so, retry...             */
  1157. "        sub   %0, %0, #1;n"           /* Decrement ulRet             */
  1158. "        cmp   %0, #0x80000000;n"      /* check for overflow          */
  1159. "        subeq %0, %0, #1;n"         /* if so, decrement again      */
  1160. "        str   %0, [%1];n"             /* Save new value into *pNum   */
  1161.         : "=&r" (ulRet)
  1162.         : "r" (pNum)
  1163.         : "cc", "memory"
  1164.         );
  1165.     return ulRet;
  1166. }
  1167. /* Add n */
  1168. inline void
  1169. HXAtomicAddUINT32(UINT32* pNum, UINT32 ulNum)
  1170. {
  1171.     UINT32 ulTmp;
  1172.     __asm__ __volatile__(
  1173. "        mov   %0, #0x80000000;n"      /* Set ulTmp to 0x800000000    */
  1174. "1:      swp   %0, %0, [%1];n"         /* Swap *pNum and ulTmp        */
  1175. "        cmp   %0, #0x80000000;n"      /* Is someone else using pNum? */
  1176. "        beq   1;n"                    /* If so, retry...             */
  1177. "        add   %0, %0, %2;n"           /* Add ulNum to ulTmp          */
  1178. "        cmp   %0, #0x80000000;n"      /* check for overflow          */
  1179. "        addeq %0, %0, #1;n"           /* if so, increment again      */
  1180. "        str   %0, [%1];n"             /* Save new value into *pNum   */
  1181.         : /* no output */
  1182.         : "r" (ulTmp), "r" (pNum), "r" (ulNum)
  1183.         : "cc", "memory"
  1184.         );
  1185. }
  1186. /* Subtract n */
  1187. inline void
  1188. HXAtomicSubUINT32(UINT32* pNum, UINT32 ulNum)
  1189. {
  1190.     UINT32 ulTmp;
  1191.     __asm__ __volatile__(
  1192. "        mov   %0, #0x80000000;n"      /* Set ulTmp to 0x800000000    */
  1193. "1:      swp   %0, %0, [%1];n"         /* Swap *pNum and ulTmp        */
  1194. "        cmp   %0, #0x80000000;n"      /* Is someone else using pNum? */
  1195. "        beq   1;n"                    /* If so, retry...             */
  1196. "        sub   %0, %0, %2;n"           /* Subtract ulNum from ulTmp   */
  1197. "        cmp   %0, #0x80000000;n"      /* check for overflow          */
  1198. "        subeq %0, %0, #1;n"           /* if so, decrement again      */
  1199. "        str   %0, [%1];n"             /* Save new value into *pNum   */
  1200.         : /* no output */
  1201.         : "r" (ulTmp), "r" (pNum), "r" (ulNum)
  1202.         : "cc", "memory"
  1203.         );
  1204. }
  1205. /* Add n and return new value */
  1206. inline UINT32
  1207. HXAtomicAddRetUINT32(UINT32* pNum, UINT32 ulNum)
  1208. {
  1209.     volatile UINT32 ulRet;
  1210.     __asm__ __volatile__(
  1211. "        mov   %0, #0x80000000;n"      /* Set ulRet to 0x80000000     */
  1212. "1:      swp   %0, %0, [%1];n"         /* Swap *pNum and ulRet        */
  1213. "        cmp   %0, #0x80000000;n"      /* Is someone else using pNum? */
  1214. "        beq   1;n"                    /* If so, retry...             */
  1215. "        add   %0, %0, %2;n"           /* Add ulNum to ulRet          */
  1216. "        cmp   %0, #0x80000000;n"      /* check for overflow          */
  1217. "        addeq %0, %0, #1;n"         /* if so, increment again      */
  1218. "        str   %0, [%1];n"             /* Save new value into *pNum   */
  1219.         : "=&r" (ulRet)
  1220.         : "r" (pNum) , "r" (ulNum)
  1221.         : "cc", "memory"
  1222.         );
  1223.     return ulRet;
  1224. }
  1225. /* Subtract n and return new value */
  1226. inline UINT32
  1227. HXAtomicSubRetUINT32(UINT32* pNum, UINT32 ulNum)
  1228. {   
  1229.     volatile UINT32 ulRet;
  1230.     __asm__ __volatile__(
  1231. "        mov   %0, #0x80000000;n"      /* Set ulRet to 0x80000000     */
  1232. "1:      swp   %0, %0, [%1];n"         /* Swap *pNum and ulRet        */
  1233. "        cmp   %0, #0x80000000;n"      /* Is someone else using pNum? */
  1234. "        beq   1;n"                    /* If so, retry...             */
  1235. "        sub   %0, %0, %2;n"           /* Subtract ulNum from ulRet   */
  1236. "        cmp   %0, #0x80000000;n"      /* check for overflow          */
  1237. "        subeq %0, %0, #1;n"         /* if so, decrement again      */
  1238. "        str   %0, [%1];n"             /* Save new value into *pNum   */
  1239.         : "=&r" (ulRet)
  1240.         : "r" (pNum), "r" (ulNum)
  1241.         : "cc", "memory"
  1242.         );
  1243.     return ulRet;
  1244. }
  1245. inline void HXAtomicIncINT32(INT32* p)              { HXAtomicIncUINT32((UINT32*)p); }
  1246. inline void HXAtomicDecINT32(INT32* p)              { HXAtomicDecUINT32((UINT32*)p); }
  1247. inline void HXAtomicAddINT32(INT32* p, INT32 n)     { HXAtomicAddUINT32((UINT32*)p, (UINT32)n); }
  1248. inline void HXAtomicSubINT32(INT32* p, INT32 n)     { HXAtomicSubUINT32((UINT32*)p, (UINT32)n); }
  1249. inline INT32 HXAtomicIncRetINT32(INT32* p)          { return HXAtomicIncRetUINT32((UINT32*)p); }
  1250. inline INT32 HXAtomicDecRetINT32(INT32* p)          { return HXAtomicDecRetUINT32((UINT32*)p); }
  1251. inline INT32 HXAtomicAddRetINT32(INT32* p, INT32 n) { return HXAtomicAddRetUINT32((UINT32*)p, (UINT32)n); }
  1252. inline INT32 HXAtomicSubRetINT32(INT32* p, INT32 n) { return HXAtomicSubRetUINT32((UINT32*)p, (UINT32)n); }
  1253. /***********************************************************************
  1254.  * Add new platforms above here
  1255.  */
  1256. #else
  1257. //
  1258. // Unsupported platform
  1259. //
  1260. #  ifndef HELIX_CONFIG_DISABLE_ATOMIC_OPERATORS
  1261. // Defining HELIX_CONFIG_DISABLE_ATOMIC_OPERATORS will use the ++ and --
  1262. // operators in place of atomic operators in some places in the code. These
  1263. // operators are not thread-safe, and should only be used in the intermediary
  1264. // stages of porting.
  1265. #    error "You need to create atomic dec/inc opers for your platform or #define HELIX_CONFIG_DISABLE_ATOMIC_OPERATORS"
  1266. #  endif
  1267. #endif
  1268. /*************************************************************************/
  1269. /*
  1270.  * Conditional override of InterlockedIncrement/Decrement
  1271.  *
  1272.  * Place this in your Umakefil/.pcf file to turn off atomic
  1273.  * InterlockedIncrement/Decrement on a per-module basis,
  1274.  * or place it in your umake profile for system-wide scope.
  1275.  * If this is defined you'll still have access to the underlying
  1276.  * HXAtomicxxx operators (if they exist for your platform),
  1277.  * just that the specific InterlockedIncrement/InterlockedDecrement
  1278.  * macros won't be defined to use them.
  1279.  */
  1280. #if !defined (HELIX_CONFIG_DISABLE_ATOMIC_OPERATORS)
  1281. #undef InterlockedIncrement
  1282. #undef InterlockedDecrement
  1283. // Since many classes (incorrectly) implement their refcount using LONG32
  1284. // rather than the proper ULONG32, we have to use the typecast for things
  1285. // to build on many platforms.
  1286. #define InterlockedIncrement(p) HXAtomicIncRetUINT32((UINT32*)(p))
  1287. #define InterlockedDecrement(p) HXAtomicDecRetUINT32((UINT32*)(p))
  1288. #define HAVE_INTERLOCKED_INCREMENT //so hxcom.h doesn't redefine these to ++/--
  1289. #endif /* !defined(HELIX_CONFIG_DISABLE_ATOMIC_OPERATORS) */
  1290. #endif /* _ATOMICBASE_H_ */