home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 275 / DPCS0111DVD.ISO / Toolkit / Audio-Visual / VirtualDub / Source / VirtualDub-1.9.10-src.7z / src / h / vd2 / system / atomic.h next >
Encoding:
C/C++ Source or Header  |  2009-09-14  |  9.7 KB  |  283 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    System library component
  3. //    Copyright (C) 1998-2004 Avery Lee, All Rights Reserved.
  4. //
  5. //    Beginning with 1.6.0, the VirtualDub system library is licensed
  6. //    differently than the remainder of VirtualDub.  This particular file is
  7. //    thus licensed as follows (the "zlib" license):
  8. //
  9. //    This software is provided 'as-is', without any express or implied
  10. //    warranty.  In no event will the authors be held liable for any
  11. //    damages arising from the use of this software.
  12. //
  13. //    Permission is granted to anyone to use this software for any purpose,
  14. //    including commercial applications, and to alter it and redistribute it
  15. //    freely, subject to the following restrictions:
  16. //
  17. //    1.    The origin of this software must not be misrepresented; you must
  18. //        not claim that you wrote the original software. If you use this
  19. //        software in a product, an acknowledgment in the product
  20. //        documentation would be appreciated but is not required.
  21. //    2.    Altered source versions must be plainly marked as such, and must
  22. //        not be misrepresented as being the original software.
  23. //    3.    This notice may not be removed or altered from any source
  24. //        distribution.
  25.  
  26. #ifndef f_VD2_SYSTEM_ATOMIC_H
  27. #define f_VD2_SYSTEM_ATOMIC_H
  28.  
  29. #include <vd2/system/vdtypes.h>
  30.  
  31. // Intrinsics available in VC6.0
  32. extern "C" long __cdecl _InterlockedDecrement(volatile long *p);
  33. extern "C" long __cdecl _InterlockedIncrement(volatile long *p);
  34. extern "C" long __cdecl _InterlockedCompareExchange(volatile long *p, long n, long p_compare);
  35. extern "C" long __cdecl _InterlockedExchange(volatile long *p, long n);
  36. extern "C" long __cdecl _InterlockedExchangeAdd(volatile long *p, long n);
  37.  
  38. #pragma intrinsic(_InterlockedDecrement)
  39. #pragma intrinsic(_InterlockedIncrement)
  40. #pragma intrinsic(_InterlockedCompareExchange)
  41. #pragma intrinsic(_InterlockedExchange)
  42. #pragma intrinsic(_InterlockedExchangeAdd)
  43.  
  44. // Intrinsics available in VC7.1. Note that the compiler is smart enough to
  45. // use straight LOCK AND/OR/XOR if the return value is not needed; otherwise
  46. // it uses a LOCK CMPXCHG loop.
  47. #if _MSC_VER >= 1310
  48.     extern "C" long __cdecl _InterlockedAnd(volatile long *p, long n);
  49.     extern "C" long __cdecl _InterlockedOr(volatile long *p, long n);
  50.     extern "C" long __cdecl _InterlockedXor(volatile long *p, long n);
  51.  
  52.     #pragma intrinsic(_InterlockedAnd)
  53.     #pragma intrinsic(_InterlockedOr)
  54.     #pragma intrinsic(_InterlockedXor)
  55. #endif
  56.  
  57. // Intrinsics available with AMD64
  58. #ifdef _M_AMD64
  59.     extern "C" void *__cdecl _InterlockedExchangePointer(void *volatile *pp, void *p);
  60.     #pragma intrinsic(_InterlockedExchangePointer)
  61.     extern "C" void *__cdecl _InterlockedCompareExchangePointer(void *volatile *pp, void *p, void *compare);
  62.     #pragma intrinsic(_InterlockedCompareExchangePointer)
  63. #endif
  64.  
  65. inline void *VDAtomicCompareExchangePointer(void *volatile *pp, void *p, void *compare) {
  66. #ifdef _M_AMD64
  67.     return _InterlockedCompareExchangePointer(pp, p, compare);
  68. #else
  69.     return (void *)(sintptr)_InterlockedCompareExchange((volatile long *)(volatile sintptr *)pp, (long)(sintptr)p, (long)(sintptr)compare);
  70. #endif
  71. }
  72.  
  73. ///////////////////////////////////////////////////////////////////////////
  74. /// \class VDAtomicInt
  75. /// \brief Wrapped integer supporting thread-safe atomic operations.
  76. ///
  77. /// VDAtomicInt allows integer values shared between threads to be
  78. /// modified with several common operations in a lock-less manner and
  79. /// without the need for explicit barriers. This is particularly useful
  80. /// for thread-safe reference counting.
  81. ///
  82. class VDAtomicInt {
  83. protected:
  84.     volatile int n;
  85.  
  86. public:
  87.     VDAtomicInt() {}
  88.     VDAtomicInt(int v) : n(v) {}
  89.  
  90.     bool operator!() const { return !n; }
  91.     bool operator!=(volatile int v) const  { return n!=v; }
  92.     bool operator==(volatile int v) const { return n==v; }
  93.     bool operator<=(volatile int v) const { return n<=v; }
  94.     bool operator>=(volatile int v) const { return n>=v; }
  95.     bool operator<(volatile int v) const { return n<v; }
  96.     bool operator>(volatile int v) const { return n>v; }
  97.  
  98.     ///////////////////////////////
  99.  
  100.     /// Atomically exchanges a value with an integer in memory.
  101.     static inline int staticExchange(volatile int *dst, int v) {
  102.         return (int)_InterlockedExchange((volatile long *)dst, v);
  103.     }
  104.  
  105.     /// Atomically adds one to an integer in memory.
  106.     static inline void staticIncrement(volatile int *dst) {
  107.         _InterlockedExchangeAdd((volatile long *)dst, 1);
  108.     }
  109.  
  110.     /// Atomically subtracts one from an integer in memory.
  111.     static inline void staticDecrement(volatile int *dst) {
  112.         _InterlockedExchangeAdd((volatile long *)dst, -1);
  113.     }
  114.  
  115.     /// Atomically subtracts one from an integer in memory and returns
  116.     /// true if the result is zero.
  117.     static inline bool staticDecrementTestZero(volatile int *dst) {
  118.         return 1 == _InterlockedExchangeAdd((volatile long *)dst, -1);
  119.     }
  120.  
  121.     /// Atomically adds a value to an integer in memory and returns the
  122.     /// result.
  123.     static inline int staticAdd(volatile int *dst, int v) {
  124.         return (int)_InterlockedExchangeAdd((volatile long *)dst, v) + v;
  125.     }
  126.  
  127.     /// Atomically adds a value to an integer in memory and returns the
  128.     /// old result (post-add).
  129.     static inline int staticExchangeAdd(volatile int *dst, int v) {
  130.         return _InterlockedExchangeAdd((volatile long *)dst, v);
  131.     }
  132.  
  133.     /// Atomically compares an integer in memory to a compare value and
  134.     /// swaps the memory location with a second value if the compare
  135.     /// succeeds. The return value is the memory value prior to the swap.
  136.     static inline int staticCompareExchange(volatile int *dst, int v, int compare) {
  137.         return _InterlockedCompareExchange((volatile long *)dst, v, compare);
  138.     }
  139.  
  140.     ///////////////////////////////
  141.  
  142.     int operator=(int v) { return n = v; }
  143.  
  144.     int operator++()        { return staticAdd(&n, 1); }
  145.     int operator--()        { return staticAdd(&n, -1); }
  146.     int operator++(int)        { return staticExchangeAdd(&n, 1); }
  147.     int operator--(int)        { return staticExchangeAdd(&n, -1); }
  148.     int operator+=(int v)    { return staticAdd(&n, v); }
  149.     int operator-=(int v)    { return staticAdd(&n, -v); }
  150.  
  151. #if _MSC_VER >= 1310
  152.     void operator&=(int v)    { _InterlockedAnd((volatile long *)&n, v); }    ///< Atomic bitwise AND.
  153.     void operator|=(int v)    { _InterlockedOr((volatile long *)&n, v); }        ///< Atomic bitwise OR.
  154.     void operator^=(int v)    { _InterlockedXor((volatile long *)&n, v); }    ///< Atomic bitwise XOR.
  155. #else
  156.     /// Atomic bitwise AND.
  157.     void operator&=(int v) {
  158.         __asm mov eax,v
  159.         __asm mov ecx,this
  160.         __asm lock and dword ptr [ecx],eax
  161.     }
  162.  
  163.     /// Atomic bitwise OR.
  164.     void operator|=(int v) {
  165.         __asm mov eax,v
  166.         __asm mov ecx,this
  167.         __asm lock or dword ptr [ecx],eax
  168.     }
  169.  
  170.     /// Atomic bitwise XOR.
  171.     void operator^=(int v) {
  172.         __asm mov eax,v
  173.         __asm mov ecx,this
  174.         __asm lock xor dword ptr [ecx],eax
  175.     }
  176. #endif
  177.  
  178.     operator int() const {
  179.         return n;
  180.     }
  181.  
  182.     /// Atomic exchange.
  183.     int xchg(int v) {
  184.         return staticExchange(&n, v);
  185.     }
  186.  
  187.     /// Compare/exchange (486+).
  188.     int compareExchange(int newValue, int oldValue) {
  189.         return staticCompareExchange(&n, newValue, oldValue);
  190.     }
  191.  
  192.     // 486 only, but much nicer.  They return the actual result.
  193.  
  194.     int inc()            { return operator++(); }                ///< Atomic increment.
  195.     int dec()            { return operator--(); }                ///< Atomic decrement.
  196.     int add(int v)        { return operator+=(v); }                ///< Atomic add.
  197.  
  198.     // These return the result before the operation, which is more inline with
  199.     // what XADD allows us to do.
  200.  
  201.     int postinc()        { return operator++(0); }                ///< Atomic post-increment.
  202.     int postdec()        { return operator--(0); }                ///< Atomic post-decrement.
  203.     int postadd(int v)    { return staticExchangeAdd(&n, v); }    ///< Atomic post-add.
  204.  
  205. };
  206.  
  207. ///////////////////////////////////////////////////////////////////////////
  208.  
  209. class VDAtomicFloat {
  210. protected:
  211.     volatile float n;
  212.  
  213. public:
  214.     VDAtomicFloat() {}
  215.     VDAtomicFloat(float v) : n(v) {}
  216.  
  217.     bool operator!=(float v) const  { return n!=v; }
  218.     bool operator==(float v) const { return n==v; }
  219.     bool operator<=(float v) const { return n<=v; }
  220.     bool operator>=(float v) const { return n>=v; }
  221.     bool operator<(float v) const { return n<v; }
  222.     bool operator>(float v) const { return n>v; }
  223.  
  224.     float operator=(float v) { return n = v; }
  225.  
  226.     operator float() const {
  227.         return n;
  228.     }
  229.  
  230.     /// Atomic exchange.
  231.     float xchg(float v) {
  232.         union { int i; float f; } converter = {VDAtomicInt::staticExchange((volatile int *)&n, *(const int *)&v)};
  233.  
  234.         return converter.f;
  235.     }
  236. };
  237.  
  238. ///////////////////////////////////////////////////////////////////////////
  239. /// \class VDAtomicPtr
  240. /// \brief Wrapped pointer supporting thread-safe atomic operations.
  241. ///
  242. /// VDAtomicPtr allows a shared pointer to be safely manipulated by
  243. /// multiple threads without locks. Note that atomicity is only guaranteed
  244. /// for the pointer itself, so any operations on the object must be dealt
  245. /// with in other manners, such as an inner lock or other atomic
  246. /// operations. An atomic pointer can serve as a single entry queue.
  247. ///
  248. template<typename T>
  249. class VDAtomicPtr {
  250. protected:
  251.     T *volatile ptr;
  252.  
  253. public:
  254.     VDAtomicPtr() {}
  255.     VDAtomicPtr(T *p) : ptr(p) { }
  256.  
  257.     operator T*() const { return ptr; }
  258.     T* operator->() const { return ptr; }
  259.  
  260.     T* operator=(T* p) {
  261.         return ptr = p;
  262.     }
  263.  
  264.     /// Atomic pointer exchange.
  265.     T *xchg(T* p) {
  266. #ifdef _M_AMD64
  267.         return ptr == p ? p : (T *)_InterlockedExchangePointer((void *volatile *)&ptr, p);
  268. #else
  269.         return ptr == p ? p : (T *)_InterlockedExchange((volatile long *)&ptr, (long)p);
  270. #endif
  271.     }
  272.  
  273.     T *compareExchange(T *newValue, T *oldValue) {
  274. #ifdef _M_AMD64
  275.         return (T *)_InterlockedCompareExchangePointer((void *volatile *)&ptr, (void *)newValue, (void *)oldValue);
  276. #else
  277.         return (T *)_InterlockedCompareExchange((volatile long *)&ptr, (long)(size_t)newValue, (long)(size_t)oldValue);
  278. #endif
  279.     }
  280. };
  281.  
  282. #endif
  283.