cartobase  5.0.5
ZAtomic.h
Go to the documentation of this file.
1 /* This software and supporting documentation are distributed by
2  * Institut Federatif de Recherche 49
3  * CEA/NeuroSpin, Batiment 145,
4  * 91191 Gif-sur-Yvette cedex
5  * France
6  *
7  * This software is governed by the CeCILL-B license under
8  * French law and abiding by the rules of distribution of free software.
9  * You can use, modify and/or redistribute the software under the
10  * terms of the CeCILL-B license as circulated by CEA, CNRS
11  * and INRIA at the following URL "http://www.cecill.info".
12  *
13  * As a counterpart to the access to the source code and rights to copy,
14  * modify and redistribute granted by the license, users are provided only
15  * with a limited warranty and the software's author, the holder of the
16  * economic rights, and the successive licensors have only limited
17  * liability.
18  *
19  * In this respect, the user's attention is drawn to the risks associated
20  * with loading, using, modifying and/or developing or reproducing the
21  * software by the user in light of its specific status of free software,
22  * that may mean that it is complicated to manipulate, and that also
23  * therefore means that it is reserved for developers and experienced
24  * professionals having in-depth computer knowledge. Users are therefore
25  * encouraged to load and test the software's suitability as regards their
26  * requirements in conditions enabling the security of their systems and/or
27  * data to be ensured and, more generally, to use and operate it in the
28  * same conditions as regards security.
29  *
30  * The fact that you are presently reading this means that you have had
31  * knowledge of the CeCILL-B license and that you accept its terms.
32  */
33 
34 #ifndef __ZAtomic__
35 #define __ZAtomic__ 1
36 #include "zconfig.h"
37 
38 #include "ZDebug.h" // For ZAssertCompile
39 
40 // AG 2000-02-06. Much of the code in this file inlines. For that to work we need the various compilers
41 // to see quite different code. The first section of this file is #ifed out of existence, but should be
42 // considered to be the canonical API. The second section has the various versions of the real code.
43 
44 struct ZAtomic_t
45  {
46  volatile int fValue;
47  };
48 
49 // Ensure that ZAtomic_t packs properly
50 ZAssertCompile(sizeof(ZAtomic_t) == sizeof(int));
51 
52 #if 0
53 int ZAtomic_Get(const ZAtomic_t* inValueAddress);
54 int ZAtomic_Set(ZAtomic_t* inValueAddress, int inParam);
55 int ZAtomic_Add(ZAtomic_t* inValueAddress, int inParam);
56 int ZAtomic_And(ZAtomic_t* inValueAddress, int inParam);
57 int ZAtomic_Or(ZAtomic_t* inValueAddress, int inParam);
58 int ZAtomic_Xor(ZAtomic_t* inValueAddress, int inParam);
59 
60 bool ZAtomic_DecAndTest(ZAtomic_t* inValueAddress);
61 void ZAtomic_Inc(ZAtomic_t* inValueAddress);
62 void ZAtomic_Dec(ZAtomic_t* inValueAddress);
63 
64 #endif
65 
66 // ====================================================================================================
67 #if (ZCONFIG_Compiler_CodeWarrior == ZCONFIG_Compiler) && (ZCONFIG_Processor_68K == ZCONFIG_Processor)
68 #pragma mark -
69 #pragma mark * CodeWarrior/68K
70 
71 inline int ZAtomic_Get(const ZAtomic_t* inValueAddress)
72  { return inValueAddress->fValue; }
73 
74 int ZAtomic_Set(ZAtomic_t* inValueAddress : __A0, int inParam : __D1);
75 int ZAtomic_Add(ZAtomic_t* inValueAddress : __A0, int inParam : __D1);
76 int ZAtomic_And(ZAtomic_t* inValueAddress : __A0, int inParam : __D1);
77 int ZAtomic_Or(ZAtomic_t* inValueAddress : __A0, int inParam : __D1);
78 int ZAtomic_Xor(ZAtomic_t* inValueAddress : __A0, int inParam : __D1);
79 
80 asm inline bool ZAtomic_DecAndTest(ZAtomic_t* : __A0)
81  {
82  subq.l #1, (a0)
83  seq d0
84  }
85 
86 asm inline void ZAtomic_Inc(ZAtomic_t* : __A0)
87  {
88  add.l #1, (a0)
89  }
90 
91 asm inline void ZAtomic_Dec(ZAtomic_t* : __A0)
92  {
93  sub.l #1, (a0)
94  }
95 
96 // ====================================================================================================
97 #elif (ZCONFIG_Compiler_CodeWarrior == ZCONFIG_Compiler) && (ZCONFIG_Processor_PPC == ZCONFIG_Processor)
98 #pragma mark -
99 #pragma mark * CodeWarrior/PPC
100 
101 // Although CW can inline PPC assembler, for some reason it has a hard time satisfying the constraints of enclosing
102 // code and the inlined stuff simultaneously. We're able to use one (!) register in inlined code, but almost all this code
103 // requires two or more. The code is thus defined out of line in ZAtomic.cpp. The penalty for doing so is not as bad as
104 // it might seem, given that they are leaf routines and thus can be switched to/returned from in one clock cycle.
105 
106 inline int ZAtomic_Get(const ZAtomic_t* inValueAddress)
107  { return inValueAddress->fValue; }
108 
109 int ZAtomic_Set(register ZAtomic_t* inValueAddress, register int inParam);
110 
111 int ZAtomic_Add(ZAtomic_t* inValueAddress, int inParam);
112 int ZAtomic_And(ZAtomic_t* inValueAddress, int inParam);
113 int ZAtomic_Or(ZAtomic_t* inValueAddress, int inParam);
114 int ZAtomic_Xor(ZAtomic_t* inValueAddress, int inParam);
115 
116 bool ZAtomic_DecAndTest(ZAtomic_t* inValueAddress);
117 void ZAtomic_Inc(ZAtomic_t* inValueAddress);
118 void ZAtomic_Dec(ZAtomic_t* inValueAddress);
119 
120 // ====================================================================================================
121 #elif (ZCONFIG_Compiler_CodeWarrior == ZCONFIG_Compiler) && (ZCONFIG_Processor_x86 == ZCONFIG_Processor)
122 #pragma mark -
123 #pragma mark * CodeWarrior/Intel x86
124 
125 // CodeWarrior sucks rocks when it comes to reliably including inline x86 assmbly with general C/C++ code, or
126 // generating the correct opcodes for parameters. To work around the problem the code has to do superfluous
127 // register/register transfers, causing massive bloat. So for the time being these routines are defined out of
128 // line in ZAtomic.cpp, which will also make it easier to tweak them without having massive rebuilds.
129 
130 inline int ZAtomic_Get(const ZAtomic_t* inValueAddress)
131  { return inValueAddress->fValue; }
132 
133 int ZAtomic_Set(register ZAtomic_t* inValueAddress, int inParam);
134 
135 int ZAtomic_Add(ZAtomic_t* inValueAddress, int inParam);
136 int ZAtomic_And(ZAtomic_t* inValueAddress, int inParam);
137 int ZAtomic_Or(ZAtomic_t* inValueAddress, int inParam);
138 int ZAtomic_Xor(ZAtomic_t* inValueAddress, int inParam);
139 
140 bool ZAtomic_DecAndTest(ZAtomic_t* inValueAddress);
141 void ZAtomic_Inc(ZAtomic_t* inValueAddress);
142 void ZAtomic_Dec(ZAtomic_t* inValueAddress);
143 
144 // ====================================================================================================
145 #elif (ZCONFIG_Compiler_GCC == ZCONFIG_Compiler) && (ZCONFIG_Processor_x86 == ZCONFIG_Processor)
146 #if 0 // denis 2005/12/09 this causes warnings and is unused by gcc4
147 #pragma mark -
148 #pragma mark * GCC/Intel x86
149 #endif
150 
151 // AG 2000-02-08. My install of RedHat Linux, upgraded to egcs 1.0b1, does not know
152 // how to assemble >386 instructions. For now I'm just injecting the bytes manually.
153 // So, don't mess with the assignment of values to registers.
154 
155 #if defined(__i486__) || defined(__i586__) || defined(__i686__)
156 # define ZAtomic_cmpxchg "lock; cmpxchg %%ecx, (%%esi)\n"
157 #else
158 # define ZAtomic_cmpxchg ".byte 0xF0, 0x0F, 0xB1, 0x0E\n" // (which is lock; cmpxchg %ecx, (%esi)
159 #endif
160 
161 #define ZAtomic_Op_Macro(theOp) \
162  int oldValue, dummy1, dummy2; \
163  asm volatile \
164  ( \
165  "1: mov (%1), %0\n" \
166  "mov %0, %%ecx\n" \
167  #theOp" %2, %%ecx\n" \
168  ZAtomic_cmpxchg \
169  "jne 1b" \
170  : "=a" (oldValue), "=&S" (dummy1), "=&d" (dummy2) \
171  : "1" (inValueAddress), "2" (inParam) \
172  : "ecx", "cc" \
173  ); \
174  return oldValue;
175 
176 inline int ZAtomic_Get(const ZAtomic_t* inValueAddress)
177  { return inValueAddress->fValue; }
178 
179 inline int ZAtomic_Set(ZAtomic_t* inValueAddress, int inParam)
180  {
181  asm volatile
182  (
183  "lock; xchg %0, (%1)"
184  : "+q" (inParam)
185  : "q" (inValueAddress)
186  : "cc", "memory"
187  );
188  return inParam;
189  }
190 
191 inline int ZAtomic_Add(ZAtomic_t* inValueAddress, int inParam)
192  {
193  asm volatile
194  (
195  "lock; xadd %0, (%1)"
196  : "+q" (inParam)
197  : "q" (inValueAddress)
198  : "cc", "memory"
199  );
200  return inParam;
201  }
202 
203 inline int ZAtomic_And(ZAtomic_t* inValueAddress, int inParam)
204  {
205  ZAtomic_Op_Macro(and)
206  }
207 
208 inline int ZAtomic_Or(ZAtomic_t* inValueAddress, int inParam)
209  {
210  ZAtomic_Op_Macro(or)
211  }
212 
213 inline int ZAtomic_Xor(ZAtomic_t* inValueAddress, int inParam)
214  {
215  ZAtomic_Op_Macro(xor)
216  }
217 
218 inline bool ZAtomic_DecAndTest(ZAtomic_t* inValueAddress)
219  {
220  bool isZero;
221  asm volatile
222  (
223  "lock; decl (%1)\n"
224  "sete %0"
225  : "=q" (isZero)
226  : "q" (inValueAddress)
227  : "cc", "memory"
228  );
229  return isZero;
230  }
231 
232 inline void ZAtomic_Inc(ZAtomic_t* inValueAddress)
233  {
234  asm volatile
235  (
236  "lock; incl (%0)"
237  : // No outputs
238  : "q" (inValueAddress)
239  : "cc", "memory"
240  );
241  }
242 
243 inline void ZAtomic_Dec(ZAtomic_t* inValueAddress)
244  {
245  asm volatile
246  (
247  "lock; decl (%0)"
248  : // No outputs
249  : "q" (inValueAddress)
250  : "cc", "memory"
251  );
252  }
253 
254 #undef ZAtomic_cmpxchg
255 #undef ZAtomic_Op_Macro
256 
257 // ====================================================================================================
258 #elif (ZCONFIG_Compiler_GCC == ZCONFIG_Compiler) && (ZCONFIG_Processor_PPC == ZCONFIG_Processor)
259 #pragma mark -
260 #pragma mark * GCC/PPC
261 
262 #define ZAtomic_Op_Macro(theOp) \
263  int oldValue; \
264  int newValue; \
265  asm volatile \
266  ( \
267  "1: lwarx %1, 0, %4\n" \
268  #theOp" %0, %1, %3\n" \
269  "stwcx. %0, 0, %4\n" \
270  "bne 1b" \
271  : "=&r" (newValue), "=&r" (oldValue), "=m" (*inValueAddress) \
272  : "r" (inParam), "r" (inValueAddress) \
273  : "cc" \
274  ); \
275  return oldValue;
276 
277 inline int ZAtomic_Get(const ZAtomic_t* inValueAddress)
278  { return inValueAddress->fValue; }
279 
280 inline int ZAtomic_Set(ZAtomic_t* inValueAddress, int inParam)
281  {
282  int oldValue;
283  asm volatile
284  (
285  "1: lwarx %0, 0, %3\n"
286  "stwcx. %2, 0, %3\n"
287  "bne 1b"
288  : "=&r" (oldValue), "=m" (*inValueAddress)
289  : "r" (inParam), "r" (inValueAddress)
290  : "cc"
291  );
292  return oldValue;
293  }
294 
295 inline int ZAtomic_Add(ZAtomic_t* inValueAddress, int inParam)
296  {
297  ZAtomic_Op_Macro(add)
298  }
299 
300 inline int ZAtomic_And(register ZAtomic_t* inValueAddress, register int inParam)
301  {
302  ZAtomic_Op_Macro(and)
303  }
304 
305 inline int ZAtomic_Or(register ZAtomic_t* inValueAddress, register int inParam)
306  {
307  ZAtomic_Op_Macro(or)
308  }
309 
310 inline int ZAtomic_Xor(register ZAtomic_t* inValueAddress, register int inParam)
311  {
312  ZAtomic_Op_Macro(xor)
313  }
314 
315 inline bool ZAtomic_DecAndTest(ZAtomic_t* inValueAddress)
316  {
317  return ZAtomic_Add(inValueAddress, -1) == 1;
318  }
319 
320 inline void ZAtomic_Inc(ZAtomic_t* inValueAddress)
321  {
322  ZAtomic_Add(inValueAddress, 1);
323  }
324 
325 inline void ZAtomic_Dec(ZAtomic_t* inValueAddress)
326  {
327  ZAtomic_Add(inValueAddress, -1);
328  }
329 
330 // ====================================================================================================
331 #elif (ZCONFIG_Compiler_MSVC == ZCONFIG_Compiler) && (ZCONFIG_Processor_x86 == ZCONFIG_Processor)
332 #pragma mark -
333 #pragma mark * MSVC/Intel x86
334 
335 // Defined out of line in ZAtomic.cpp till I can determine how effective MSVC is at
336 // inlining assembly code.
337 
338 inline int ZAtomic_Get(const ZAtomic_t* inValueAddress)
339  { return inValueAddress->fValue; }
340 
341 int ZAtomic_Set(register ZAtomic_t* inValueAddress, int inParam);
342 
343 int ZAtomic_Add(ZAtomic_t* inValueAddress, int inParam);
344 int ZAtomic_And(ZAtomic_t* inValueAddress, int inParam);
345 int ZAtomic_Or(ZAtomic_t* inValueAddress, int inParam);
346 int ZAtomic_Xor(ZAtomic_t* inValueAddress, int inParam);
347 
348 bool ZAtomic_DecAndTest(ZAtomic_t* inValueAddress);
349 void ZAtomic_Inc(ZAtomic_t* inValueAddress);
350 void ZAtomic_Dec(ZAtomic_t* inValueAddress);
351 
352 
353 // ====================================================================================================
354 #else // ZCONFIG_Compiler/ZCONFIG_Processor
355 #pragma mark -
356 #pragma mark * Dumb version
357 
358 // Defined out of line in ZAtomic.cpp, using a global mutex to ensure atomicity. Performance will not
359 // be great, but it will at least work everywhere that we have a ZThread implementation.
360 
361 inline int ZAtomic_Get(const ZAtomic_t* inValueAddress)
362  { return inValueAddress->fValue; }
363 
364 int ZAtomic_Set(register ZAtomic_t* inValueAddress, int inParam);
365 
366 int ZAtomic_Add(ZAtomic_t* inValueAddress, int inParam);
367 int ZAtomic_And(ZAtomic_t* inValueAddress, int inParam);
368 int ZAtomic_Or(ZAtomic_t* inValueAddress, int inParam);
369 int ZAtomic_Xor(ZAtomic_t* inValueAddress, int inParam);
370 
371 bool ZAtomic_DecAndTest(ZAtomic_t* inValueAddress);
372 void ZAtomic_Inc(ZAtomic_t* inValueAddress);
373 void ZAtomic_Dec(ZAtomic_t* inValueAddress);
374 
375 #endif // ZCONFIG_Compiler/ZCONFIG_Processor
376 
377 // ====================================================================================================
378 
379 
380 
381 #endif // __ZAtomic__
ZAssertCompile(sizeof(ZAtomic_t)==sizeof(int))
int ZAtomic_Get(const ZAtomic_t *inValueAddress)
Definition: ZAtomic.h:361
bool ZAtomic_DecAndTest(ZAtomic_t *inValueAddress)
void ZAtomic_Inc(ZAtomic_t *inValueAddress)
void ZAtomic_Dec(ZAtomic_t *inValueAddress)
#define ZCONFIG_Compiler_CodeWarrior
Definition: zconfigd.h:41
int ZAtomic_Set(register ZAtomic_t *inValueAddress, int inParam)
volatile int fValue
Definition: ZAtomic.h:46
int ZAtomic_And(ZAtomic_t *inValueAddress, int inParam)
int ZAtomic_Xor(ZAtomic_t *inValueAddress, int inParam)
#define ZCONFIG_Processor_PPC
Definition: zconfigd.h:58
int ZAtomic_Or(ZAtomic_t *inValueAddress, int inParam)
int ZAtomic_Add(ZAtomic_t *inValueAddress, int inParam)