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