Panda3D
|
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 }