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 #ifdef _M_IX86 00024 // Windows case 00025 TVOLATILE Integer *var_ptr = &var; 00026 __asm { 00027 mov edx, var_ptr; 00028 lock inc dword ptr [edx]; 00029 } 00030 #elif !defined(__EDG__) 00031 // GCC case 00032 __asm__ __volatile__("lock; incl %0" 00033 :"=m" (var) 00034 :"m" (&var)); 00035 #endif // __EDG__ 00036 } 00037 00038 //////////////////////////////////////////////////////////////////// 00039 // Function: AtomicAdjustI386Impl::dec 00040 // Access: Public, Static 00041 // Description: Atomically decrements the indicated variable and 00042 // returns true if the new value is nonzero, false if it 00043 // is zero. 00044 //////////////////////////////////////////////////////////////////// 00045 INLINE bool AtomicAdjustI386Impl:: 00046 dec(TVOLATILE AtomicAdjustI386Impl::Integer &var) { 00047 unsigned char c; 00048 #ifdef _M_IX86 00049 // Windows case 00050 TVOLATILE Integer *var_ptr = &var; 00051 __asm { 00052 mov edx, var_ptr; 00053 lock dec dword ptr [edx]; 00054 sete c; 00055 } 00056 #elif !defined(__EDG__) 00057 // GCC case 00058 __asm__ __volatile__("lock; decl %0; sete %1" 00059 :"=m" (var), "=qm" (c) 00060 :"m" (&var) : "memory"); 00061 #endif // __EDG__ 00062 return (c == 0); 00063 } 00064 00065 //////////////////////////////////////////////////////////////////// 00066 // Function: AtomicAdjustI386Impl::add 00067 // Access: Public, Static 00068 // Description: Atomically computes var += delta. It is legal for 00069 // delta to be negative. 00070 //////////////////////////////////////////////////////////////////// 00071 INLINE void AtomicAdjustI386Impl:: 00072 add(TVOLATILE AtomicAdjustI386Impl::Integer &var, AtomicAdjustI386Impl::Integer delta) { 00073 Integer orig_value = var; 00074 while (compare_and_exchange(var, orig_value, orig_value + delta) != orig_value) { 00075 orig_value = var; 00076 } 00077 } 00078 00079 //////////////////////////////////////////////////////////////////// 00080 // Function: AtomicAdjustI386Impl::set 00081 // Access: Public, Static 00082 // Description: Atomically changes the indicated variable and 00083 // returns the original value. 00084 //////////////////////////////////////////////////////////////////// 00085 INLINE AtomicAdjustI386Impl::Integer AtomicAdjustI386Impl:: 00086 set(TVOLATILE AtomicAdjustI386Impl::Integer &var, AtomicAdjustI386Impl::Integer new_value) { 00087 Integer orig_value = var; 00088 var = new_value; 00089 return orig_value; 00090 } 00091 00092 //////////////////////////////////////////////////////////////////// 00093 // Function: AtomicAdjustI386Impl::get 00094 // Access: Public, Static 00095 // Description: Atomically retrieves the snapshot value of the 00096 // indicated variable. This is the only guaranteed safe 00097 // way to retrieve the value that other threads might be 00098 // asynchronously setting, incrementing, or decrementing 00099 // (via other AtomicAjust methods). 00100 //////////////////////////////////////////////////////////////////// 00101 INLINE AtomicAdjustI386Impl::Integer AtomicAdjustI386Impl:: 00102 get(const TVOLATILE AtomicAdjustI386Impl::Integer &var) { 00103 return var; 00104 } 00105 00106 //////////////////////////////////////////////////////////////////// 00107 // Function: AtomicAdjustI386Impl::set_ptr 00108 // Access: Public, Static 00109 // Description: Atomically changes the indicated variable and 00110 // returns the original value. 00111 //////////////////////////////////////////////////////////////////// 00112 INLINE void *AtomicAdjustI386Impl:: 00113 set_ptr(void * TVOLATILE &var, void *new_value) { 00114 void *orig_value = var; 00115 var = new_value; 00116 return orig_value; 00117 } 00118 00119 //////////////////////////////////////////////////////////////////// 00120 // Function: AtomicAdjustI386Impl::get_ptr 00121 // Access: Public, Static 00122 // Description: Atomically retrieves the snapshot value of the 00123 // indicated variable. This is the only guaranteed safe 00124 // way to retrieve the value that other threads might be 00125 // asynchronously setting, incrementing, or decrementing 00126 // (via other AtomicAjust methods). 00127 //////////////////////////////////////////////////////////////////// 00128 INLINE void *AtomicAdjustI386Impl:: 00129 get_ptr(void * const TVOLATILE &var) { 00130 return var; 00131 } 00132 00133 //////////////////////////////////////////////////////////////////// 00134 // Function: AtomicAdjustI386Impl::compare_and_exchange 00135 // Access: Public, Static 00136 // Description: Atomic compare and exchange. 00137 // 00138 // If mem is equal to old_value, store new_value in mem. 00139 // In either case, return the original value of mem. 00140 // The caller can test for success by comparing 00141 // return_value == old_value. 00142 // 00143 // The atomic function expressed in pseudo-code: 00144 // 00145 // orig_value = mem; 00146 // if (mem == old_value) { 00147 // mem = new_value; 00148 // } 00149 // return orig_value; 00150 // 00151 //////////////////////////////////////////////////////////////////// 00152 INLINE AtomicAdjustI386Impl::Integer AtomicAdjustI386Impl:: 00153 compare_and_exchange(TVOLATILE AtomicAdjustI386Impl::Integer &mem, AtomicAdjustI386Impl::Integer old_value, 00154 AtomicAdjustI386Impl::Integer new_value) { 00155 Integer prev; 00156 #ifdef _M_IX86 00157 // Windows case 00158 TVOLATILE Integer *mem_ptr = &mem; 00159 __asm { 00160 mov edx, mem_ptr; 00161 mov ecx, new_value; 00162 mov eax, old_value; 00163 lock cmpxchg dword ptr [edx], ecx; 00164 mov prev, eax; 00165 } 00166 #elif !defined(__EDG__) 00167 // GCC case 00168 __asm__ __volatile__("lock; cmpxchgl %1,%2" 00169 : "=a"(prev) 00170 : "r"(new_value), "m"(mem), "0"(old_value) 00171 : "memory"); 00172 #endif // __EDG__ 00173 return prev; 00174 } 00175 00176 //////////////////////////////////////////////////////////////////// 00177 // Function: AtomicAdjustI386Impl::compare_and_exchange_ptr 00178 // Access: Public, Static 00179 // Description: Atomic compare and exchange. 00180 // 00181 // As above, but works on pointers instead of integers. 00182 //////////////////////////////////////////////////////////////////// 00183 INLINE void *AtomicAdjustI386Impl:: 00184 compare_and_exchange_ptr(void * TVOLATILE &mem, void *old_value, 00185 void *new_value) { 00186 void *prev; 00187 #ifdef _M_IX86 00188 // Windows case 00189 void * TVOLATILE *mem_ptr = &mem; 00190 __asm { 00191 mov edx, mem_ptr; 00192 mov ecx, new_value; 00193 mov eax, old_value; 00194 lock cmpxchg dword ptr [edx], ecx; 00195 mov prev, eax; 00196 } 00197 #elif !defined(__EDG__) 00198 // GCC case 00199 __asm__ __volatile__("lock; cmpxchgl %1,%2" 00200 : "=a"(prev) 00201 : "r"(new_value), "m"(mem), "0"(old_value) 00202 : "memory"); 00203 #endif // __EDG__ 00204 return prev; 00205 }