Panda3D
 All Classes Functions Variables Enumerations
atomicAdjustI386Impl.I
00001 // Filename: atomicAdjustI386Impl.I
00002 // Created by:  drose (01Apr06)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 
00016 ////////////////////////////////////////////////////////////////////
00017 //     Function: AtomicAdjustI386Impl::inc
00018 //       Access: Public, Static
00019 //  Description: Atomically increments the indicated variable.
00020 ////////////////////////////////////////////////////////////////////
00021 INLINE void AtomicAdjustI386Impl::
00022 inc(TVOLATILE AtomicAdjustI386Impl::Integer &var) {
00023   assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0);
00024 #ifdef _M_IX86
00025   // Windows case
00026   TVOLATILE Integer *var_ptr = &var;
00027   __asm {
00028     mov edx, var_ptr;
00029     lock inc dword ptr [edx];
00030   }
00031 #elif !defined(__EDG__)
00032   // GCC case
00033   __asm__ __volatile__("lock; incl %0"
00034                        :"=m" (var)
00035                        :"m" (&var));
00036 #endif  // __EDG__
00037 }
00038 
00039 ////////////////////////////////////////////////////////////////////
00040 //     Function: AtomicAdjustI386Impl::dec
00041 //       Access: Public, Static
00042 //  Description: Atomically decrements the indicated variable and
00043 //               returns true if the new value is nonzero, false if it
00044 //               is zero.
00045 ////////////////////////////////////////////////////////////////////
00046 INLINE bool AtomicAdjustI386Impl::
00047 dec(TVOLATILE AtomicAdjustI386Impl::Integer &var) {
00048   assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0);
00049   unsigned char c;
00050 #ifdef _M_IX86
00051   // Windows case
00052   TVOLATILE Integer *var_ptr = &var;
00053   __asm {
00054     mov edx, var_ptr;
00055     lock dec dword ptr [edx];
00056     sete c;
00057   }
00058 #elif !defined(__EDG__)
00059   // GCC case
00060   __asm__ __volatile__("lock; decl %0; sete %1"
00061                        :"=m" (var), "=qm" (c)
00062                        :"m" (&var) : "memory");
00063 #endif  // __EDG__
00064   return (c == 0);
00065 }
00066 
00067 ////////////////////////////////////////////////////////////////////
00068 //     Function: AtomicAdjustI386Impl::add
00069 //       Access: Public, Static
00070 //  Description: Atomically computes var += delta.  It is legal for
00071 //               delta to be negative.
00072 ////////////////////////////////////////////////////////////////////
00073 INLINE void AtomicAdjustI386Impl::
00074 add(TVOLATILE AtomicAdjustI386Impl::Integer &var, AtomicAdjustI386Impl::Integer delta) {
00075   assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0);
00076   Integer orig_value = var;
00077   while (compare_and_exchange(var, orig_value, orig_value + delta) != orig_value) {
00078     orig_value = var;
00079   }
00080 }
00081 
00082 ////////////////////////////////////////////////////////////////////
00083 //     Function: AtomicAdjustI386Impl::set
00084 //       Access: Public, Static
00085 //  Description: Atomically changes the indicated variable and
00086 //               returns the original value.
00087 ////////////////////////////////////////////////////////////////////
00088 INLINE AtomicAdjustI386Impl::Integer AtomicAdjustI386Impl::
00089 set(TVOLATILE AtomicAdjustI386Impl::Integer &var, 
00090     AtomicAdjustI386Impl::Integer new_value) {
00091   assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0);
00092   Integer orig_value = var;
00093   var = new_value;
00094   return orig_value;
00095 }
00096 
00097 ////////////////////////////////////////////////////////////////////
00098 //     Function: AtomicAdjustI386Impl::get
00099 //       Access: Public, Static
00100 //  Description: Atomically retrieves the snapshot value of the
00101 //               indicated variable.  This is the only guaranteed safe
00102 //               way to retrieve the value that other threads might be
00103 //               asynchronously setting, incrementing, or decrementing
00104 //               (via other AtomicAjust methods).
00105 ////////////////////////////////////////////////////////////////////
00106 INLINE AtomicAdjustI386Impl::Integer AtomicAdjustI386Impl::
00107 get(const TVOLATILE AtomicAdjustI386Impl::Integer &var) {
00108   assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0);
00109   return var;
00110 }
00111 
00112 ////////////////////////////////////////////////////////////////////
00113 //     Function: AtomicAdjustI386Impl::set_ptr
00114 //       Access: Public, Static
00115 //  Description: Atomically changes the indicated variable and
00116 //               returns the original value.
00117 ////////////////////////////////////////////////////////////////////
00118 INLINE AtomicAdjustI386Impl::Pointer AtomicAdjustI386Impl::
00119 set_ptr(TVOLATILE AtomicAdjustI386Impl::Pointer &var, 
00120         AtomicAdjustI386Impl::Pointer new_value) {
00121   assert((((size_t)&var) & (sizeof(Pointer) - 1)) == 0);
00122   Pointer orig_value = var;
00123   var = new_value;
00124   return orig_value;
00125 }
00126 
00127 ////////////////////////////////////////////////////////////////////
00128 //     Function: AtomicAdjustI386Impl::get_ptr
00129 //       Access: Public, Static
00130 //  Description: Atomically retrieves the snapshot value of the
00131 //               indicated variable.  This is the only guaranteed safe
00132 //               way to retrieve the value that other threads might be
00133 //               asynchronously setting, incrementing, or decrementing
00134 //               (via other AtomicAjust methods).
00135 ////////////////////////////////////////////////////////////////////
00136 INLINE AtomicAdjustI386Impl::Pointer AtomicAdjustI386Impl::
00137 get_ptr(const TVOLATILE AtomicAdjustI386Impl::Pointer &var) {
00138   assert((((size_t)&var) & (sizeof(Pointer) - 1)) == 0);
00139   return var;
00140 }
00141 
00142 ////////////////////////////////////////////////////////////////////
00143 //     Function: AtomicAdjustI386Impl::compare_and_exchange
00144 //       Access: Public, Static
00145 //  Description: Atomic compare and exchange.  
00146 //
00147 //               If mem is equal to old_value, store new_value in mem.
00148 //               In either case, return the original value of mem.
00149 //               The caller can test for success by comparing
00150 //               return_value == old_value.
00151 //
00152 //               The atomic function expressed in pseudo-code:
00153 //
00154 //                 orig_value = mem;
00155 //                 if (mem == old_value) {
00156 //                   mem = new_value;
00157 //                 }
00158 //                 return orig_value;
00159 //
00160 ////////////////////////////////////////////////////////////////////
00161 INLINE AtomicAdjustI386Impl::Integer AtomicAdjustI386Impl::
00162 compare_and_exchange(TVOLATILE AtomicAdjustI386Impl::Integer &mem, 
00163                      AtomicAdjustI386Impl::Integer old_value,
00164                      AtomicAdjustI386Impl::Integer new_value) {
00165   assert((((size_t)&mem) & (sizeof(Integer) - 1)) == 0);
00166   Integer prev;
00167 #ifdef _M_IX86
00168   // Windows case
00169   TVOLATILE Integer *mem_ptr = &mem;
00170   __asm {
00171     mov edx, mem_ptr;
00172     mov ecx, new_value;
00173     mov eax, old_value;
00174     lock cmpxchg dword ptr [edx], ecx;
00175     mov prev, eax;
00176   }
00177 #elif !defined(__EDG__)
00178   // GCC case
00179   __asm__ __volatile__("lock; cmpxchgl %1,%2"
00180                        : "=a"(prev)
00181                        : "r"(new_value), "m"(mem), "0"(old_value)
00182                        : "memory");
00183 #endif  // __EDG__
00184   return prev;
00185 }
00186 
00187 ////////////////////////////////////////////////////////////////////
00188 //     Function: AtomicAdjustI386Impl::compare_and_exchange_ptr
00189 //       Access: Public, Static
00190 //  Description: Atomic compare and exchange.  
00191 //
00192 //               As above, but works on pointers instead of integers.
00193 ////////////////////////////////////////////////////////////////////
00194 INLINE AtomicAdjustI386Impl::Pointer AtomicAdjustI386Impl::
00195 compare_and_exchange_ptr(TVOLATILE AtomicAdjustI386Impl::Pointer &mem, 
00196                          AtomicAdjustI386Impl::Pointer old_value,
00197                          AtomicAdjustI386Impl::Pointer new_value) {
00198   assert((((size_t)&mem) & (sizeof(Pointer) - 1)) == 0);
00199   Pointer prev;
00200 #ifdef _M_IX86
00201   // Windows case
00202   TVOLATILE Pointer *mem_ptr = &mem;
00203   __asm {
00204     mov edx, mem_ptr;
00205     mov ecx, new_value;
00206     mov eax, old_value;
00207     lock cmpxchg dword ptr [edx], ecx;
00208     mov prev, eax;
00209   }
00210 #elif !defined(__EDG__)
00211   // GCC case
00212   __asm__ __volatile__("lock; cmpxchgl %1,%2"
00213                        : "=a"(prev)
00214                        : "r"(new_value), "m"(mem), "0"(old_value)
00215                        : "memory");
00216 #endif  // __EDG__
00217   return prev;
00218 }
 All Classes Functions Variables Enumerations