ncbicntr.hpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:15k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbicntr.hpp,v $
  4.  * PRODUCTION Revision 1000.4  2004/06/01 19:07:55  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.24
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. #ifndef NCBICNTR__HPP
  10. #define NCBICNTR__HPP
  11. /*  $Id: ncbicntr.hpp,v 1000.4 2004/06/01 19:07:55 gouriano Exp $
  12. * ===========================================================================
  13. *
  14. *                            PUBLIC DOMAIN NOTICE
  15. *               National Center for Biotechnology Information
  16. *
  17. *  This software/database is a "United States Government Work" under the
  18. *  terms of the United States Copyright Act.  It was written as part of
  19. *  the author's official duties as a United States Government employee and
  20. *  thus cannot be copyrighted.  This software/database is freely available
  21. *  to the public for use. The National Library of Medicine and the U.S.
  22. *  Government have not placed any restriction on its use or reproduction.
  23. *
  24. *  Although all reasonable efforts have been taken to ensure the accuracy
  25. *  and reliability of the software and data, the NLM and the U.S.
  26. *  Government do not and cannot warrant the performance or results that
  27. *  may be obtained by using this software or data. The NLM and the U.S.
  28. *  Government disclaim all warranties, express or implied, including
  29. *  warranties of performance, merchantability or fitness for any particular
  30. *  purpose.
  31. *
  32. *  Please cite the author in any work or product based on this material.
  33. *
  34. * ===========================================================================
  35. *
  36. * Author:  Aaron Ucko
  37. *
  38. *
  39. */
  40. /// @file ncbictr.hpp
  41. /// Efficient atomic counters (for CObject reference counts)
  42. /// Note that the special value 0x3FFFFFFF is used to indicate
  43. /// locked counters on some platforms.
  44. #include <corelib/ncbistd.hpp>
  45. #if defined(HAVE_SCHED_YIELD) && !defined(NCBI_NO_THREADS)
  46. extern "C" {
  47. #  include <sched.h>
  48. }
  49. #  define NCBI_SCHED_INIT() int spin_counter = 0
  50. #  define NCBI_SCHED_YIELD() if ( !(++spin_counter & 3) ) sched_yield()
  51. #else
  52. #  define NCBI_SCHED_INIT()
  53. #  define NCBI_SCHED_YIELD()
  54. #endif
  55. #ifdef NCBI_COMPILER_GCC
  56. #  if NCBI_COMPILER_VERSION >= 300
  57. #    define NCBI_COMPILER_GCC3 1
  58. #  endif
  59. #elif defined(NCBI_COMPILER_ICC)
  60. #  if NCBI_COMPILER_VERSION >= 600
  61. #    define NCBI_COMPILER_ICC6
  62. #  endif
  63. #endif
  64. #undef NCBI_COUNTER_UNSIGNED
  65. #undef NCBI_COUNTER_RESERVED_VALUE
  66. #undef NCBI_COUNTER_ASM_OK
  67. #undef NCBI_COUNTER_USE_ASM
  68. #undef NCBI_COUNTER_ADD
  69. #undef NCBI_COUNTER_NEED_MUTEX
  70. // Messy system-specific details; they're mostly grouped together here
  71. // to ensure consistency.
  72. #if defined(NCBI_COMPILER_GCC) || defined(NCBI_COMPILER_WORKSHOP) || (defined(NCBI_COMPILER_KCC) && defined(NCBI_OS_LINUX)) || defined(NCBI_COMPILER_ICC6)
  73. #  define NCBI_COUNTER_ASM_OK
  74. #endif
  75. /// Define platform specific counter-related macros/values.
  76. ///
  77. /// TNCBIAtomicValue "type" is defined based on facilities available for a
  78. /// compiler/platform. TNCBIAtomicValue is used in the CAtomicCounter class
  79. /// for defining the internal represntation of the counter.
  80. ///
  81. /// Where possible NCBI_COUNTER_ADD is defined in terms of compiler/platform
  82. /// specific features.
  83. #ifdef NCBI_NO_THREADS
  84.    typedef unsigned int TNCBIAtomicValue;
  85. #  define NCBI_COUNTER_UNSIGNED 1
  86. #  define NCBI_COUNTER_ADD(p, d) ((*p) += d)
  87. #elif defined(NCBI_COUNTER_ASM_OK) && defined(__sparc) && !defined(__sparcv9)
  88. // Always use our own code on pre-V9 SPARC; GCC 3's implementation
  89. // uses a global lock.
  90.    typedef unsigned int TNCBIAtomicValue;
  91. #  define NCBI_COUNTER_UNSIGNED 1
  92. #  define NCBI_COUNTER_RESERVED_VALUE 0x3FFFFFFF
  93. #  define NCBI_COUNTER_USE_ASM 1
  94. #elif defined(NCBI_COMPILER_GCC3)
  95. #  include <bits/atomicity.h>
  96.    typedef _Atomic_word TNCBIAtomicValue;
  97. #  if NCBI_COMPILER_VERSION >= 340
  98. #    define NCBI_COUNTER_ADD(p, d) (__gnu_cxx::__exchange_and_add(p, d) + d)
  99. #  else
  100. #    define NCBI_COUNTER_ADD(p, d) (__exchange_and_add(p, d) + d)
  101. #  endif
  102. #elif defined(NCBI_COMPILER_COMPAQ)
  103. #  include <machine/builtins.h>
  104.    typedef int TNCBIAtomicValue;
  105. #  define NCBI_COUNTER_ADD(p, d) (__ATOMIC_ADD_LONG(p, d) + d)
  106. #elif defined(NCBI_OS_SOLARIS) && 0 // Kernel-only. :-/
  107. #  include <sys/atomic.h>
  108.    typedef uint32_t TNCBIAtomicValue;
  109. #  define NCBI_COUNTER_UNSIGNED 1
  110. #  define NCBI_COUNTER_ADD(p, d) atomic_add_32_nv(p, d)
  111. #elif defined(NCBI_OS_IRIX)
  112. #  include <mutex.h>
  113.    typedef __uint32_t TNCBIAtomicValue;
  114. #  define NCBI_COUNTER_UNSIGNED 1
  115. #  define NCBI_COUNTER_ADD(p, d) add_then_test32(p, d)
  116. #elif defined(NCBI_OS_AIX)
  117. #  include <sys/atomic_op.h>
  118.    typedef int TNCBIAtomicValue;
  119. #  define NCBI_COUNTER_ADD(p, d) (fetch_and_add(p, d) + d)
  120. #elif defined(NCBI_OS_DARWIN)
  121. #  ifdef __MWERKS__
  122.     // necessary so Metrowerks can compile the following header properly
  123.     // unfortunately, there's no way to save the old value of the macro,
  124.     // so NCBI_verify_save must be just a flag.
  125. #    define __NOEXTENSIONS__
  126. #    ifdef verify
  127. #      define NCBI_verify_save verify
  128. #      undef verify
  129. #    endif
  130. #  endif
  131. #  include <CoreServices/CoreServices.h>
  132. // Darwin's <AssertMacros.h> defines check as a variant of assert....
  133. #  ifdef check
  134. #    undef check
  135. #  endif
  136. #  ifdef NCBI_verify_save
  137. #    undef verify
  138. #    if defined(NDEBUG) || !defined(_DEBUG)
  139. #      define verify(expr) (void) expr
  140. #    else
  141. #      define verify(expr) assert(expr)
  142. #    endif
  143. #  endif
  144.    typedef SInt32 TNCBIAtomicValue;
  145. #  define NCBI_COUNTER_ADD(p, d) (AddAtomic(d, p) + d)
  146. #elif defined(NCBI_OS_MAC)
  147. #  include <OpenTransport.h> // Is this right?
  148.    typedef SInt32 TNCBIAtomicValue;
  149. #  define NCBI_COUNTER_ADD(p, d) OTAtomicAdd32(d, p)
  150. #elif defined(NCBI_OS_MSWIN)
  151. #  include <corelib/ncbi_os_mswin.hpp>
  152.    typedef LONG TNCBIAtomicValue;
  153. #  define NCBI_COUNTER_ADD(p, d) (InterlockedExchangeAdd(p, d) + d)
  154. #else
  155.    typedef unsigned int TNCBIAtomicValue;
  156. #  define NCBI_COUNTER_UNSIGNED 1
  157. #  if defined (NCBI_COUNTER_ASM_OK) && (defined(__i386) || defined(__sparc))
  158. #    define NCBI_COUNTER_USE_ASM 1
  159. #  else
  160. #    define NCBI_COUNTER_NEED_MUTEX 1
  161. #  endif
  162. #endif
  163. /** @addtogroup Counters
  164.  *
  165.  * @{
  166.  */
  167. BEGIN_NCBI_SCOPE
  168. /////////////////////////////////////////////////////////////////////////////
  169. ///
  170. /// CAtomicCounter --
  171. ///
  172. /// Define a basic atomic counter.
  173. ///
  174. /// Provide basic counter operations for an atomic counter represented
  175. /// internally by TNCBIAtomicValue. 
  176. class CAtomicCounter
  177. {
  178. public:
  179.     typedef TNCBIAtomicValue TValue;  ///< Alias TValue for TNCBIAtomicValue
  180.     /// Get atomic counter value.
  181.     TValue Get(void) const THROWS_NONE;
  182.     /// Set atomic counter value.
  183.     void   Set(TValue new_value) THROWS_NONE;
  184.     /// Atomically add value (=delta), and return new counter value.
  185.     TValue Add(int delta) THROWS_NONE;
  186.     
  187.     /// Define NCBI_COUNTER_ADD if one has not been defined.
  188. #if defined(NCBI_COUNTER_USE_ASM)
  189.     static TValue x_Add(volatile TValue* value, int delta) THROWS_NONE;
  190. #  if !defined(NCBI_COUNTER_ADD)
  191. #     define NCBI_COUNTER_ADD(value, delta) NCBI_NS_NCBI::CAtomicCounter::x_Add((value), (delta))
  192. #  endif
  193. #endif
  194. private:
  195.     volatile TValue m_Value;  ///< Internal counter value
  196.     // CObject's constructor needs to read m_Value directly when checking
  197.     // for the magic number left by operator new.
  198.     friend class CObject;
  199. };
  200. /////////////////////////////////////////////////////////////////////////////
  201. ///
  202. /// CMutableAtomicCounter --
  203. ///
  204. /// Define a mutable atomic counter.
  205. ///
  206. /// Provide mutable counter operations for an atomic counter represented
  207. /// internally by CAtomicCounter. 
  208. class NCBI_XNCBI_EXPORT CMutableAtomicCounter
  209. {
  210. public:
  211.     typedef CAtomicCounter::TValue TValue; ///< Alias TValue simplifies syntax
  212.     /// Get atomic counter value.
  213.     TValue Get(void) const THROWS_NONE
  214.         { return m_Counter.Get(); }
  215.     /// Set atomic counter value.
  216.     void   Set(TValue new_value) const THROWS_NONE
  217.         { m_Counter.Set(new_value); }
  218.     /// Atomically add value (=delta), and return new counter value.
  219.     TValue Add(int delta) const THROWS_NONE
  220.         { return m_Counter.Add(delta); }
  221. private:
  222.     mutable CAtomicCounter m_Counter;      ///< Mutable atomic counter value
  223. };
  224. /* @} */
  225. //////////////////////////////////////////////////////////////////////
  226. // 
  227. // Inline methods
  228. inline
  229. CAtomicCounter::TValue CAtomicCounter::Get(void) const THROWS_NONE
  230. {
  231. #ifdef NCBI_COUNTER_RESERVED_VALUE
  232.     TValue value = m_Value;
  233.     NCBI_SCHED_INIT();
  234.     while (value == NCBI_COUNTER_RESERVED_VALUE) {
  235.         NCBI_SCHED_YIELD();
  236.         value = m_Value;
  237.     }
  238.     return value;
  239. #else
  240.     return m_Value;
  241. #endif
  242. }
  243. inline
  244. void CAtomicCounter::Set(CAtomicCounter::TValue new_value) THROWS_NONE
  245. {
  246.     m_Value = new_value;
  247. }
  248. // With WorkShop, sanely inlining assembly requires the use of ".il" files.
  249. // In order to keep the toolkit's external interface sane, we therefore
  250. // force this method out-of-line and into ncbicntr_workshop.o.
  251. #if defined(NCBI_COUNTER_USE_ASM) && (!defined(NCBI_COMPILER_WORKSHOP) || defined(NCBI_COUNTER_IMPLEMENTATION))
  252. #  ifdef NCBI_COMPILER_WORKSHOP
  253. #    ifdef __sparcv9
  254. extern "C"
  255. CAtomicCounter::TValue NCBICORE_asm_cas(CAtomicCounter::TValue new_value,
  256.                                         CAtomicCounter::TValue* address,
  257.                                         CAtomicCounter::TValue old_value);
  258. #    elif defined(__sparc)
  259. extern "C"
  260. CAtomicCounter::TValue NCBICORE_asm_swap(CAtomicCounter::TValue new_value,
  261.                                          CAtomicCounter::TValue* address);
  262. #    elif defined(__i386)
  263. extern "C"
  264. CAtomicCounter::TValue NCBICORE_asm_lock_xaddl(CAtomicCounter::TValue* address,
  265.                                                int delta);
  266. #    endif
  267. #  else
  268. inline
  269. #  endif
  270. CAtomicCounter::TValue
  271. CAtomicCounter::x_Add(volatile CAtomicCounter::TValue* value_p, int delta)
  272. THROWS_NONE
  273. {
  274.     TValue result;
  275.     TValue* nv_value_p = const_cast<TValue*>(value_p);
  276. #  ifdef __sparcv9
  277.     NCBI_SCHED_INIT();
  278.     for (;;) {
  279.         TValue old_value = *value_p;
  280.         result = old_value + delta;
  281.         // Atomic compare-and-swap: if *value_p == old_value, swap it
  282.         // with result; otherwise, just put the current value in result.
  283. #    ifdef NCBI_COMPILER_WORKSHOP
  284.         result = NCBICORE_asm_cas(result, nv_value_p, old_value);
  285. #    else
  286.         asm volatile("cas [%3], %2, %1" : "=m" (*nv_value_p), "+r" (result)
  287.                      : "r" (old_value), "r" (nv_value_p), "m" (*nv_value_p));
  288. #    endif
  289.         if (result == old_value) { // We win
  290.             break;
  291.         }
  292.         NCBI_SCHED_YIELD();
  293.     }
  294.     result += delta;
  295. #  elif defined(__sparc)
  296.     result = NCBI_COUNTER_RESERVED_VALUE;
  297.     NCBI_SCHED_INIT();
  298.     for (;;) {
  299. #    ifdef NCBI_COMPILER_WORKSHOP
  300.         result = NCBICORE_asm_swap(result, nv_value_p);
  301. #    else
  302.         asm volatile("swap [%2], %1" : "=m" (*nv_value_p), "+r" (result)
  303.                      : "r" (nv_value_p), "m" (*nv_value_p));
  304. #    endif
  305.         if (result != NCBI_COUNTER_RESERVED_VALUE) {
  306.             break;
  307.         }
  308.         NCBI_SCHED_YIELD();
  309.     }
  310.     result += delta;
  311.     *value_p = result;
  312. #  elif defined(__i386)
  313.     // Yay CISC. ;-)
  314. #    ifdef NCBI_COMPILER_WORKSHOP
  315.     result = NCBICORE_asm_lock_xaddl(nv_value_p, delta) + delta;
  316. #    else
  317.     asm volatile("lock; xaddl %1, %0" : "=m" (*nv_value_p), "=r" (result)
  318.                  : "1" (delta), "m" (*nv_value_p));
  319.     result += delta;
  320. #    endif
  321. #  else
  322. #    error "Unsupported processor type for assembly implementation!"
  323. #  endif
  324.     return result;
  325. }
  326. #endif
  327. #if !defined(NCBI_COUNTER_NEED_MUTEX)
  328. inline
  329. CAtomicCounter::TValue CAtomicCounter::Add(int delta) THROWS_NONE
  330. {
  331.     TValue* nv_value_p = const_cast<TValue*>(&m_Value);
  332.     return NCBI_COUNTER_ADD(nv_value_p, delta);
  333. }
  334. #endif
  335. END_NCBI_SCOPE
  336. /*
  337. * ===========================================================================
  338. *
  339. * $Log: ncbicntr.hpp,v $
  340. * Revision 1000.4  2004/06/01 19:07:55  gouriano
  341. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.24
  342. *
  343. * Revision 1.24  2004/05/14 16:15:41  dicuccio
  344. * Remove unneeded export specifier for CAtomicCounter - the class is entirely
  345. * inline for MSVC
  346. *
  347. * Revision 1.23  2004/04/26 14:31:46  ucko
  348. * GCC 3.4 has moved __exchange_and_add to the __gnu_cxx namespace.
  349. * Split up "+m" constraints for GCC assembly, as versions 3.4 and up
  350. * complain about them.
  351. *
  352. * Revision 1.22  2004/02/19 16:46:21  vasilche
  353. * Added spin counter before calling sched_yield().
  354. * Use volatile version of pointer for assignment in x_Add().
  355. *
  356. * Revision 1.21  2004/02/18 23:28:46  ucko
  357. * Clean up after previous (mislogged) commit, and honor volatility better.
  358. *
  359. * Revision 1.20  2004/02/17 20:35:23  rsmith
  360. * Deal with stray definition of verify() on Mac.
  361. *
  362. * Revision 1.19  2004/02/04 00:38:03  ucko
  363. * Centralize undefinition of Darwin's check macro.
  364. *
  365. * Revision 1.18  2004/02/03 19:28:30  ucko
  366. * Darwin: include the master CoreServices header because
  367. * DriverSynchronization.h is officially internal.
  368. *
  369. * Revision 1.17  2003/07/11 12:47:09  siyan
  370. * Documentation changes.
  371. *
  372. * Revision 1.16  2003/06/03 18:24:28  rsmith
  373. * wrap includes of sched.h (explicit and implicit) in extern "c" blocks, since Apples headers do not do it themselves.
  374. *
  375. * Revision 1.15  2003/06/03 15:35:07  rsmith
  376. * OS_DARWIN's AddAtomic returns the previous value, not the incremented value as we require.
  377. *
  378. * Revision 1.14  2003/05/23 18:16:07  rsmith
  379. * proper definitions for NCBI_COUNTER_ADD on Mac/Darwin
  380. *
  381. * Revision 1.13  2003/03/31 14:07:04  siyan
  382. * Added doxygen support
  383. *
  384. * Revision 1.12  2003/03/06 19:38:48  ucko
  385. * Make CObject a friend, so that InitCounter can read m_Value directly
  386. * rather than going through Get(), which would end up spinning forever
  387. * if it came across NCBI_COUNTER_RESERVED_VALUE.
  388. *
  389. * Revision 1.11  2002/12/18 22:53:21  dicuccio
  390. * Added export specifier for building DLLs in windows.  Added global list of
  391. * all such specifiers in mswin_exports.hpp, included through ncbistl.hpp
  392. *
  393. * Revision 1.10  2002/10/30 17:14:33  ucko
  394. * Enable inline asm for ICC 6, which seems to be okay with our (modern) syntax.
  395. *
  396. * Revision 1.9  2002/09/20 13:51:04  vasilche
  397. * Fixed volatile argument to NCBI_COUNTER_ADD
  398. *
  399. * Revision 1.8  2002/09/19 20:05:41  vasilche
  400. * Safe initialization of static mutexes
  401. *
  402. * Revision 1.7  2002/08/19 19:37:17  vakatov
  403. * Use <corelib/ncbi_os_mswin.hpp> in the place of <windows.h>
  404. *
  405. * Revision 1.6  2002/07/11 14:17:53  gouriano
  406. * exceptions replaced by CNcbiException-type ones
  407. *
  408. * Revision 1.5  2002/05/31 17:48:56  grichenk
  409. * +CMutableAtomicCounter
  410. *
  411. * Revision 1.4  2002/05/24 18:43:34  ucko
  412. * Use trivial implementation for single-threaded builds.
  413. *
  414. * Revision 1.3  2002/05/24 18:06:55  ucko
  415. * Inline assembly leads to ICC compiler errors in some cases, so stop
  416. * defining NCBI_COUNTER_ASM_OK for ICC.
  417. *
  418. * Revision 1.2  2002/05/24 14:20:04  ucko
  419. * Fix Intel extended assembly.
  420. * Drop use of FreeBSD <machine/atomic.h>; those functions return void.
  421. * Fix name of "nv_value_p" in Add(), and declare it only when needed.
  422. *
  423. * Revision 1.1  2002/05/23 22:24:21  ucko
  424. * Use low-level atomic operations for reference counts
  425. *
  426. *
  427. * ===========================================================================
  428. */
  429. #endif  /* NCBICNTR__HPP */