cartobase 6.0.6
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
45 {
46 volatile int fValue;
47 };
48
49// Ensure that ZAtomic_t packs properly
50ZAssertCompile(sizeof(ZAtomic_t) == sizeof(int));
51
52#if 0
53int ZAtomic_Get(const ZAtomic_t* inValueAddress);
54int ZAtomic_Set(ZAtomic_t* inValueAddress, int inParam);
55int ZAtomic_Add(ZAtomic_t* inValueAddress, int inParam);
56int ZAtomic_And(ZAtomic_t* inValueAddress, int inParam);
57int ZAtomic_Or(ZAtomic_t* inValueAddress, int inParam);
58int ZAtomic_Xor(ZAtomic_t* inValueAddress, int inParam);
59
60bool ZAtomic_DecAndTest(ZAtomic_t* inValueAddress);
61void ZAtomic_Inc(ZAtomic_t* inValueAddress);
62void 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
71inline int ZAtomic_Get(const ZAtomic_t* inValueAddress)
72 { return inValueAddress->fValue; }
73
74int ZAtomic_Set(ZAtomic_t* inValueAddress : __A0, int inParam : __D1);
75int ZAtomic_Add(ZAtomic_t* inValueAddress : __A0, int inParam : __D1);
76int ZAtomic_And(ZAtomic_t* inValueAddress : __A0, int inParam : __D1);
77int ZAtomic_Or(ZAtomic_t* inValueAddress : __A0, int inParam : __D1);
78int ZAtomic_Xor(ZAtomic_t* inValueAddress : __A0, int inParam : __D1);
79
80asm inline bool ZAtomic_DecAndTest(ZAtomic_t* : __A0)
81 {
82 subq.l #1, (a0)
83 seq d0
84 }
85
86asm inline void ZAtomic_Inc(ZAtomic_t* : __A0)
87 {
88 add.l #1, (a0)
89 }
90
91asm 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
106inline int ZAtomic_Get(const ZAtomic_t* inValueAddress)
107 { return inValueAddress->fValue; }
108
109int ZAtomic_Set(register ZAtomic_t* inValueAddress, register int inParam);
110
111int ZAtomic_Add(ZAtomic_t* inValueAddress, int inParam);
112int ZAtomic_And(ZAtomic_t* inValueAddress, int inParam);
113int ZAtomic_Or(ZAtomic_t* inValueAddress, int inParam);
114int ZAtomic_Xor(ZAtomic_t* inValueAddress, int inParam);
115
116bool ZAtomic_DecAndTest(ZAtomic_t* inValueAddress);
117void ZAtomic_Inc(ZAtomic_t* inValueAddress);
118void 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
130inline int ZAtomic_Get(const ZAtomic_t* inValueAddress)
131 { return inValueAddress->fValue; }
132
133int ZAtomic_Set(register ZAtomic_t* inValueAddress, int inParam);
134
135int ZAtomic_Add(ZAtomic_t* inValueAddress, int inParam);
136int ZAtomic_And(ZAtomic_t* inValueAddress, int inParam);
137int ZAtomic_Or(ZAtomic_t* inValueAddress, int inParam);
138int ZAtomic_Xor(ZAtomic_t* inValueAddress, int inParam);
139
140bool ZAtomic_DecAndTest(ZAtomic_t* inValueAddress);
141void ZAtomic_Inc(ZAtomic_t* inValueAddress);
142void 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
176inline int ZAtomic_Get(const ZAtomic_t* inValueAddress)
177 { return inValueAddress->fValue; }
178
179inline 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
191inline 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
203inline int ZAtomic_And(ZAtomic_t* inValueAddress, int inParam)
204 {
205 ZAtomic_Op_Macro(and)
206 }
207
208inline int ZAtomic_Or(ZAtomic_t* inValueAddress, int inParam)
209 {
210 ZAtomic_Op_Macro(or)
211 }
212
213inline int ZAtomic_Xor(ZAtomic_t* inValueAddress, int inParam)
214 {
215 ZAtomic_Op_Macro(xor)
216 }
217
218inline 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
232inline 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
243inline 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
277inline int ZAtomic_Get(const ZAtomic_t* inValueAddress)
278 { return inValueAddress->fValue; }
279
280inline 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
295inline int ZAtomic_Add(ZAtomic_t* inValueAddress, int inParam)
296 {
297 ZAtomic_Op_Macro(add)
298 }
299
300inline int ZAtomic_And(register ZAtomic_t* inValueAddress, register int inParam)
301 {
302 ZAtomic_Op_Macro(and)
303 }
304
305inline int ZAtomic_Or(register ZAtomic_t* inValueAddress, register int inParam)
306 {
307 ZAtomic_Op_Macro(or)
308 }
309
310inline int ZAtomic_Xor(register ZAtomic_t* inValueAddress, register int inParam)
311 {
312 ZAtomic_Op_Macro(xor)
313 }
314
315inline bool ZAtomic_DecAndTest(ZAtomic_t* inValueAddress)
316 {
317 return ZAtomic_Add(inValueAddress, -1) == 1;
318 }
319
320inline void ZAtomic_Inc(ZAtomic_t* inValueAddress)
321 {
322 ZAtomic_Add(inValueAddress, 1);
323 }
324
325inline 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
338inline int ZAtomic_Get(const ZAtomic_t* inValueAddress)
339 { return inValueAddress->fValue; }
340
341int ZAtomic_Set(register ZAtomic_t* inValueAddress, int inParam);
342
343int ZAtomic_Add(ZAtomic_t* inValueAddress, int inParam);
344int ZAtomic_And(ZAtomic_t* inValueAddress, int inParam);
345int ZAtomic_Or(ZAtomic_t* inValueAddress, int inParam);
346int ZAtomic_Xor(ZAtomic_t* inValueAddress, int inParam);
347
348bool ZAtomic_DecAndTest(ZAtomic_t* inValueAddress);
349void ZAtomic_Inc(ZAtomic_t* inValueAddress);
350void 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
361inline int ZAtomic_Get(const ZAtomic_t* inValueAddress)
362 { return inValueAddress->fValue; }
363
364int ZAtomic_Set(register ZAtomic_t* inValueAddress, int inParam);
365
366int ZAtomic_Add(ZAtomic_t* inValueAddress, int inParam);
367int ZAtomic_And(ZAtomic_t* inValueAddress, int inParam);
368int ZAtomic_Or(ZAtomic_t* inValueAddress, int inParam);
369int ZAtomic_Xor(ZAtomic_t* inValueAddress, int inParam);
370
371bool ZAtomic_DecAndTest(ZAtomic_t* inValueAddress);
372void ZAtomic_Inc(ZAtomic_t* inValueAddress);
373void ZAtomic_Dec(ZAtomic_t* inValueAddress);
374
375#endif // ZCONFIG_Compiler/ZCONFIG_Processor
376
377// ====================================================================================================
378
379
380
381#endif // __ZAtomic__
int ZAtomic_Get(const ZAtomic_t *inValueAddress)
Definition ZAtomic.h:361
void ZAtomic_Inc(ZAtomic_t *inValueAddress)
void ZAtomic_Dec(ZAtomic_t *inValueAddress)
int ZAtomic_Xor(ZAtomic_t *inValueAddress, int inParam)
int ZAtomic_Or(ZAtomic_t *inValueAddress, int inParam)
int ZAtomic_Add(ZAtomic_t *inValueAddress, int inParam)
int ZAtomic_And(ZAtomic_t *inValueAddress, int inParam)
bool ZAtomic_DecAndTest(ZAtomic_t *inValueAddress)
int ZAtomic_Set(register ZAtomic_t *inValueAddress, int inParam)
#define ZAssertCompile(a)
Definition ZDebug.h:148
volatile int fValue
Definition ZAtomic.h:46