atomicbase.h
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:53k
源码类别:

Symbian

开发平台:

C/C++

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