Panda3D
 All Classes Functions Variables Enumerations
atomicAdjustI386Impl.I
1 // Filename: atomicAdjustI386Impl.I
2 // Created by: drose (01Apr06)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 
16 ////////////////////////////////////////////////////////////////////
17 // Function: AtomicAdjustI386Impl::inc
18 // Access: Public, Static
19 // Description: Atomically increments the indicated variable.
20 ////////////////////////////////////////////////////////////////////
21 INLINE void AtomicAdjustI386Impl::
22 inc(TVOLATILE AtomicAdjustI386Impl::Integer &var) {
23  assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0);
24 #ifdef _M_IX86
25  // Windows case
26  TVOLATILE Integer *var_ptr = &var;
27  __asm {
28  mov edx, var_ptr;
29  lock inc dword ptr [edx];
30  }
31 #elif !defined(__EDG__)
32  // GCC case
33  __asm__ __volatile__("lock; incl %0"
34  :"=m" (var)
35  :"m" (&var));
36 #endif // __EDG__
37 }
38 
39 ////////////////////////////////////////////////////////////////////
40 // Function: AtomicAdjustI386Impl::dec
41 // Access: Public, Static
42 // Description: Atomically decrements the indicated variable and
43 // returns true if the new value is nonzero, false if it
44 // is zero.
45 ////////////////////////////////////////////////////////////////////
46 INLINE bool AtomicAdjustI386Impl::
47 dec(TVOLATILE AtomicAdjustI386Impl::Integer &var) {
48  assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0);
49  unsigned char c;
50 #ifdef _M_IX86
51  // Windows case
52  TVOLATILE Integer *var_ptr = &var;
53  __asm {
54  mov edx, var_ptr;
55  lock dec dword ptr [edx];
56  sete c;
57  }
58 #elif !defined(__EDG__)
59  // GCC case
60  __asm__ __volatile__("lock; decl %0; sete %1"
61  :"=m" (var), "=qm" (c)
62  :"m" (&var) : "memory");
63 #endif // __EDG__
64  return (c == 0);
65 }
66 
67 ////////////////////////////////////////////////////////////////////
68 // Function: AtomicAdjustI386Impl::add
69 // Access: Public, Static
70 // Description: Atomically computes var += delta. It is legal for
71 // delta to be negative.
72 ////////////////////////////////////////////////////////////////////
73 INLINE void AtomicAdjustI386Impl::
74 add(TVOLATILE AtomicAdjustI386Impl::Integer &var, AtomicAdjustI386Impl::Integer delta) {
75  assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0);
76  Integer orig_value = var;
77  while (compare_and_exchange(var, orig_value, orig_value + delta) != orig_value) {
78  orig_value = var;
79  }
80 }
81 
82 ////////////////////////////////////////////////////////////////////
83 // Function: AtomicAdjustI386Impl::set
84 // Access: Public, Static
85 // Description: Atomically changes the indicated variable and
86 // returns the original value.
87 ////////////////////////////////////////////////////////////////////
88 INLINE AtomicAdjustI386Impl::Integer AtomicAdjustI386Impl::
89 set(TVOLATILE AtomicAdjustI386Impl::Integer &var,
90  AtomicAdjustI386Impl::Integer new_value) {
91  assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0);
92  Integer orig_value = var;
93  var = new_value;
94  return orig_value;
95 }
96 
97 ////////////////////////////////////////////////////////////////////
98 // Function: AtomicAdjustI386Impl::get
99 // Access: Public, Static
100 // Description: Atomically retrieves the snapshot value of the
101 // indicated variable. This is the only guaranteed safe
102 // way to retrieve the value that other threads might be
103 // asynchronously setting, incrementing, or decrementing
104 // (via other AtomicAjust methods).
105 ////////////////////////////////////////////////////////////////////
106 INLINE AtomicAdjustI386Impl::Integer AtomicAdjustI386Impl::
107 get(const TVOLATILE AtomicAdjustI386Impl::Integer &var) {
108  assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0);
109  return var;
110 }
111 
112 ////////////////////////////////////////////////////////////////////
113 // Function: AtomicAdjustI386Impl::set_ptr
114 // Access: Public, Static
115 // Description: Atomically changes the indicated variable and
116 // returns the original value.
117 ////////////////////////////////////////////////////////////////////
118 INLINE AtomicAdjustI386Impl::Pointer AtomicAdjustI386Impl::
119 set_ptr(TVOLATILE AtomicAdjustI386Impl::Pointer &var,
120  AtomicAdjustI386Impl::Pointer new_value) {
121  assert((((size_t)&var) & (sizeof(Pointer) - 1)) == 0);
122  Pointer orig_value = var;
123  var = new_value;
124  return orig_value;
125 }
126 
127 ////////////////////////////////////////////////////////////////////
128 // Function: AtomicAdjustI386Impl::get_ptr
129 // Access: Public, Static
130 // Description: Atomically retrieves the snapshot value of the
131 // indicated variable. This is the only guaranteed safe
132 // way to retrieve the value that other threads might be
133 // asynchronously setting, incrementing, or decrementing
134 // (via other AtomicAjust methods).
135 ////////////////////////////////////////////////////////////////////
136 INLINE AtomicAdjustI386Impl::Pointer AtomicAdjustI386Impl::
137 get_ptr(const TVOLATILE AtomicAdjustI386Impl::Pointer &var) {
138  assert((((size_t)&var) & (sizeof(Pointer) - 1)) == 0);
139  return var;
140 }
141 
142 ////////////////////////////////////////////////////////////////////
143 // Function: AtomicAdjustI386Impl::compare_and_exchange
144 // Access: Public, Static
145 // Description: Atomic compare and exchange.
146 //
147 // If mem is equal to old_value, store new_value in mem.
148 // In either case, return the original value of mem.
149 // The caller can test for success by comparing
150 // return_value == old_value.
151 //
152 // The atomic function expressed in pseudo-code:
153 //
154 // orig_value = mem;
155 // if (mem == old_value) {
156 // mem = new_value;
157 // }
158 // return orig_value;
159 //
160 ////////////////////////////////////////////////////////////////////
161 INLINE AtomicAdjustI386Impl::Integer AtomicAdjustI386Impl::
162 compare_and_exchange(TVOLATILE AtomicAdjustI386Impl::Integer &mem,
163  AtomicAdjustI386Impl::Integer old_value,
164  AtomicAdjustI386Impl::Integer new_value) {
165  assert((((size_t)&mem) & (sizeof(Integer) - 1)) == 0);
166  Integer prev;
167 #ifdef _M_IX86
168  // Windows case
169  TVOLATILE Integer *mem_ptr = &mem;
170  __asm {
171  mov edx, mem_ptr;
172  mov ecx, new_value;
173  mov eax, old_value;
174  lock cmpxchg dword ptr [edx], ecx;
175  mov prev, eax;
176  }
177 #elif !defined(__EDG__)
178  // GCC case
179  __asm__ __volatile__("lock; cmpxchgl %1,%2"
180  : "=a"(prev)
181  : "r"(new_value), "m"(mem), "0"(old_value)
182  : "memory");
183 #endif // __EDG__
184  return prev;
185 }
186 
187 ////////////////////////////////////////////////////////////////////
188 // Function: AtomicAdjustI386Impl::compare_and_exchange_ptr
189 // Access: Public, Static
190 // Description: Atomic compare and exchange.
191 //
192 // As above, but works on pointers instead of integers.
193 ////////////////////////////////////////////////////////////////////
194 INLINE AtomicAdjustI386Impl::Pointer AtomicAdjustI386Impl::
195 compare_and_exchange_ptr(TVOLATILE AtomicAdjustI386Impl::Pointer &mem,
196  AtomicAdjustI386Impl::Pointer old_value,
197  AtomicAdjustI386Impl::Pointer new_value) {
198  assert((((size_t)&mem) & (sizeof(Pointer) - 1)) == 0);
199  Pointer prev;
200 #ifdef _M_IX86
201  // Windows case
202  TVOLATILE Pointer *mem_ptr = &mem;
203  __asm {
204  mov edx, mem_ptr;
205  mov ecx, new_value;
206  mov eax, old_value;
207  lock cmpxchg dword ptr [edx], ecx;
208  mov prev, eax;
209  }
210 #elif !defined(__EDG__)
211  // GCC case
212  __asm__ __volatile__("lock; cmpxchgl %1,%2"
213  : "=a"(prev)
214  : "r"(new_value), "m"(mem), "0"(old_value)
215  : "memory");
216 #endif // __EDG__
217  return prev;
218 }